123 行
3.3 KiB
TypeScript
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>
|
|
);
|
|
}
|