文件
hyb-oa/client/src/pages/user-management/UserRoleDialog.tsx
T

123 行
3.3 KiB
TypeScript

import { useEffect, useState } from "react";
import { Button } from "../../components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "../../components/ui/dialog";
import type { UserSummary } from "../../api/users";
export interface UserRoleDialogProps {
open: boolean;
onOpenChange: (open: boolean) => void;
user: UserSummary | null;
roleOptions: Array<{ code: string; label: string }>;
onSubmit: (roles: string[]) => void;
isPending: boolean;
}
const ROLE_PRESETS = [
{ key: "owner", label: "老板", roles: ["ceo"] },
{ key: "admin", label: "管理员", roles: ["admin"] },
{ key: "employee", label: "员工", roles: ["employee"] },
{ key: "manager", label: "主管", roles: ["manager"] },
];
export function UserRoleDialog({
open,
onOpenChange,
user,
roleOptions,
onSubmit,
isPending,
}: UserRoleDialogProps) {
const [roleDraft, setRoleDraft] = useState<Set<string>>(() => new Set());
useEffect(() => {
if (user) {
setRoleDraft(new Set(user.roleCodes));
} else {
setRoleDraft(new Set());
}
}, [user]);
function handleClose() {
onOpenChange(false);
}
return (
<Dialog
open={open}
onOpenChange={(nextOpen) => {
if (!nextOpen) {
handleClose();
}
}}
>
<DialogContent className="max-w-lg">
<DialogHeader>
<DialogTitle>设置角色</DialogTitle>
<DialogDescription>
当前用户:{user?.employeeNo} / {user?.name}
</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<div className="flex flex-wrap gap-2">
{ROLE_PRESETS.map((preset) => (
<Button key={preset.key} size="sm" variant="secondary" type="button" onClick={() => setRoleDraft(new Set(preset.roles))}>
预设:{preset.label}
</Button>
))}
</div>
<div className="flex flex-wrap gap-3 text-sm">
{roleOptions.map((item) => (
<label className="flex items-center gap-2" key={item.code}>
<input
data-testid={`users-role-${item.code}`}
type="checkbox"
checked={roleDraft.has(item.code)}
onChange={(event) => {
setRoleDraft((prev) => {
const next = new Set(prev);
if (event.target.checked) {
next.add(item.code);
} else {
next.delete(item.code);
}
return next;
});
}}
/>
<span>{item.label}</span>
</label>
))}
</div>
</div>
<div className="flex justify-end gap-2">
<Button
variant="secondary"
disabled={isPending}
onClick={handleClose}
type="button"
>
取消
</Button>
<Button
data-testid="users-role-save"
disabled={isPending || roleDraft.size < 1}
onClick={() => onSubmit(Array.from(roleDraft))}
type="button"
>
{isPending ? "保存中..." : "保存"}
</Button>
</div>
</DialogContent>
</Dialog>
);
}