151 lines
6.4 KiB
TypeScript
151 lines
6.4 KiB
TypeScript
import { useState } from "react";
|
||
import { Button, Form, Input, Message, Modal, Space, Table, Tag } from "@arco-design/web-react";
|
||
import { IconPlus } from "@arco-design/web-react/icon";
|
||
import { roleApi } from "../api";
|
||
import { usePageData } from "../hooks/usePageData";
|
||
import { Panel } from "../components/Panel";
|
||
import { PermissionTreePicker } from "./components/PermissionTreePicker";
|
||
import type { CreateRoleFormValues, Permission, Role } from "./interface";
|
||
|
||
function RolesPage() {
|
||
const { data, loading, reload, changePage } = usePageData<Role>(roleApi.listRoles, { page: 1, pageSize: 20 });
|
||
const permissions = usePageData<Permission>(roleApi.listPermissions, { page: 1, pageSize: 20 });
|
||
const [createForm] = Form.useForm();
|
||
const [createVisible, setCreateVisible] = useState(false);
|
||
const [creatingRole, setCreatingRole] = useState(false);
|
||
const [createPermissionIds, setCreatePermissionIds] = useState<number[]>([]);
|
||
const [assignmentVisible, setAssignmentVisible] = useState(false);
|
||
const [selectedRole, setSelectedRole] = useState<Role | null>(null);
|
||
const [selectedPermissionIds, setSelectedPermissionIds] = useState<number[]>([]);
|
||
const [savingPermissions, setSavingPermissions] = useState(false);
|
||
|
||
const openCreateRole = () => {
|
||
createForm.resetFields();
|
||
setCreatePermissionIds([]);
|
||
setCreateVisible(true);
|
||
};
|
||
|
||
const createRole = async (values: CreateRoleFormValues) => {
|
||
setCreatingRole(true);
|
||
try {
|
||
await roleApi.createRole({
|
||
...values,
|
||
permissionIds: createPermissionIds,
|
||
});
|
||
Message.success("角色创建成功");
|
||
setCreateVisible(false);
|
||
await reload();
|
||
} finally {
|
||
setCreatingRole(false);
|
||
}
|
||
};
|
||
|
||
const openAssignPermissions = (role: Role) => {
|
||
setSelectedRole(role);
|
||
setSelectedPermissionIds(role.permissions.map((permission) => permission.id));
|
||
setAssignmentVisible(true);
|
||
};
|
||
|
||
const saveRolePermissions = async () => {
|
||
if (!selectedRole) {
|
||
return;
|
||
}
|
||
setSavingPermissions(true);
|
||
try {
|
||
await roleApi.updateRolePermissions(selectedRole.id, selectedPermissionIds);
|
||
Message.success("角色权限已更新");
|
||
setAssignmentVisible(false);
|
||
await reload();
|
||
} finally {
|
||
setSavingPermissions(false);
|
||
}
|
||
};
|
||
|
||
return (
|
||
<div className="page-stack">
|
||
<Panel
|
||
title="角色管理"
|
||
extra={
|
||
<Button type="primary" icon={<IconPlus />} onClick={openCreateRole}>
|
||
新增角色
|
||
</Button>
|
||
}
|
||
noPadding
|
||
>
|
||
<Table
|
||
rowKey="id"
|
||
loading={loading}
|
||
data={data.list}
|
||
pagination={{
|
||
current: data.pagination.page,
|
||
total: data.pagination.total,
|
||
pageSize: data.pagination.pageSize,
|
||
sizeCanChange: true,
|
||
showTotal: true,
|
||
onChange: changePage,
|
||
}}
|
||
columns={[
|
||
{ title: "ID", dataIndex: "id", width: 80 },
|
||
{ title: "编码", dataIndex: "code" },
|
||
{ title: "名称", dataIndex: "name" },
|
||
{
|
||
title: "权限列表",
|
||
render: (_, record: Role) => (
|
||
<Space wrap>
|
||
{record.permissions.map((item) => (
|
||
<Tag key={item.id}>{item.name}</Tag>
|
||
))}
|
||
</Space>
|
||
),
|
||
},
|
||
{
|
||
title: "操作",
|
||
width: 140,
|
||
render: (_, record: Role) => (
|
||
<Button size="small" onClick={() => openAssignPermissions(record)}>
|
||
分配权限
|
||
</Button>
|
||
),
|
||
},
|
||
]}
|
||
/>
|
||
<Modal title="新增角色" visible={createVisible} onCancel={() => setCreateVisible(false)} footer={null} style={{ width: "40rem" }}>
|
||
<Form form={createForm} layout="vertical" onSubmit={createRole}>
|
||
<Form.Item label="角色编码" field="code" rules={[{ required: true }]}>
|
||
<Input placeholder="请输入角色编码,例如 drama_operator" />
|
||
</Form.Item>
|
||
<div className="form-help">角色的唯一标识,创建后不可修改</div>
|
||
<Form.Item label="角色名称" field="name" rules={[{ required: true }]}>
|
||
<Input placeholder="请输入角色名称" />
|
||
</Form.Item>
|
||
<Form.Item label="角色描述" field="description">
|
||
<Input.TextArea placeholder="请输入角色描述" autoSize={{ minRows: 2, maxRows: 4 }} />
|
||
</Form.Item>
|
||
<div className="form-label">权限设置</div>
|
||
<PermissionTreePicker permissions={permissions.data.list} value={createPermissionIds} onChange={setCreatePermissionIds} />
|
||
<div className="form-help">为角色分配系统权限,决定拥有此角色的用户可以进行的操作</div>
|
||
<div className="modal-actions">
|
||
<Button onClick={() => setCreateVisible(false)}>取消</Button>
|
||
<Button type="primary" htmlType="submit" loading={creatingRole}>
|
||
创建
|
||
</Button>
|
||
</div>
|
||
</Form>
|
||
</Modal>
|
||
<Modal
|
||
title={`分配权限${selectedRole ? ` - ${selectedRole.name}` : ""}`}
|
||
visible={assignmentVisible}
|
||
confirmLoading={savingPermissions}
|
||
onOk={saveRolePermissions}
|
||
onCancel={() => setAssignmentVisible(false)}
|
||
style={{ width: "40rem" }}
|
||
>
|
||
<PermissionTreePicker permissions={permissions.data.list} value={selectedPermissionIds} onChange={setSelectedPermissionIds} />
|
||
</Modal>
|
||
</Panel>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
export default RolesPage;
|