136 lines
4.1 KiB
TypeScript
Executable File
136 lines
4.1 KiB
TypeScript
Executable File
'use client';
|
|
|
|
import * as React from 'react';
|
|
import { useState } from 'react';
|
|
import { Button } from '@nice/ui/components/button';
|
|
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@nice/ui/components/dialog';
|
|
import { Input } from '@nice/ui/components/input';
|
|
import { Label } from '@nice/ui/components/label';
|
|
import { DeptSelect, MultipleRoleSelector, SingleDeptSelector } from '@/components/selector';
|
|
import type { UserDialogState } from './types.js';
|
|
import { Textarea } from '@nice/ui/components/textarea';
|
|
|
|
// 用户对话框组件
|
|
interface UserDialogProps {
|
|
dialog: UserDialogState;
|
|
onClose: () => void;
|
|
onSave: (data: {
|
|
username: string;
|
|
roleIds: string[];
|
|
organizationId: string;
|
|
password: string;
|
|
description?: string;
|
|
}) => void;
|
|
}
|
|
|
|
export function UserDialog({ dialog, onClose, onSave }: UserDialogProps) {
|
|
const [username, setUsername] = useState(dialog.user?.username || '');
|
|
const [roleIds, setRoleIds] = useState<string[]>(dialog.user?.roleIds || []);
|
|
const [organizationId, setOrganizationId] = useState(dialog.user?.organizationId || '');
|
|
const [password, setPassword] = useState('123456');
|
|
const [description, setDescription] = useState(dialog.user?.description || '');
|
|
|
|
// 重置表单数据
|
|
React.useEffect(() => {
|
|
if (dialog.open) {
|
|
setUsername(dialog.user?.username || '');
|
|
setRoleIds(dialog.user?.roleIds || []);
|
|
setOrganizationId(dialog.user?.organizationId || '');
|
|
setPassword('123456');
|
|
setDescription(dialog.user?.description || '');
|
|
}
|
|
}, [dialog]);
|
|
|
|
const handleSave = () => {
|
|
if (!username.trim()) return;
|
|
if (roleIds.length === 0) return;
|
|
onSave({
|
|
username: username.trim(),
|
|
roleIds,
|
|
organizationId,
|
|
password,
|
|
description: description.trim(),
|
|
});
|
|
onClose();
|
|
};
|
|
|
|
const getDialogTitle = () => {
|
|
return dialog.user ? '编辑用户' : '新增用户';
|
|
};
|
|
|
|
return (
|
|
<Dialog open={dialog.open} onOpenChange={(open) => !open && onClose()}>
|
|
<DialogContent className="sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle>{getDialogTitle()}</DialogTitle>
|
|
</DialogHeader>
|
|
<div className="grid gap-4 py-4">
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="user-username">用户名</Label>
|
|
<Input
|
|
id="user-username"
|
|
placeholder="请输入用户名"
|
|
autoComplete="username"
|
|
value={username}
|
|
onChange={(e) => setUsername(e.target.value)}
|
|
/>
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="user-role">角色</Label>
|
|
<MultipleRoleSelector
|
|
value={roleIds}
|
|
onValueChange={setRoleIds}
|
|
placeholder="请选择用户角色"
|
|
showDescription={true}
|
|
showBadge={true}
|
|
className="w-full border border-[#EBEFF5]"
|
|
includeInactive={false}
|
|
modal={true}
|
|
/>
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="user-organization">所属部门</Label>
|
|
<SingleDeptSelector
|
|
value={organizationId}
|
|
onValueChange={setOrganizationId}
|
|
placeholder="选择部门"
|
|
className="w-full border border-[#EBEFF5]"
|
|
allowClear={true}
|
|
/>
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="user-description">个人简介</Label>
|
|
<Textarea
|
|
id="user-description"
|
|
placeholder="请输入个人简介(选填)"
|
|
value={description}
|
|
onChange={(e) => setDescription(e.target.value)}
|
|
className="resize-none"
|
|
rows={3}
|
|
/>
|
|
</div>
|
|
<div className="grid gap-2">
|
|
<Label htmlFor="user-password">登录密码</Label>
|
|
<Input
|
|
id="user-password"
|
|
type="password"
|
|
placeholder="请输入登录密码"
|
|
autoComplete="new-password"
|
|
value={password}
|
|
onChange={(e) => setPassword(e.target.value)}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="flex justify-end gap-2">
|
|
<Button variant="outline" className="cursor-pointer" onClick={onClose}>
|
|
取消
|
|
</Button>
|
|
<Button className="cursor-pointer" onClick={handleSave} disabled={!username.trim() || roleIds.length === 0}>
|
|
保存
|
|
</Button>
|
|
</div>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|