refactor(ui): [UI7-1] 深度翻新报销、发票与用户管理等核心视窗

这个提交包含在:
2026-03-06 09:48:11 +08:00
父节点 61180e2b3b
当前提交 c632648e16
共修改 8 个文件,包含 1105 行新增和 1250 行删除
@@ -0,0 +1,105 @@
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;
}
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="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 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>
);
}