批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换: - 翻译词典: 22 namespaces, 3600+ keys - 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy) - 语言切换器在 Header 中可用 (🇨🇳/🇺🇸) - tsc 零错误, Vite 构建成功
189 lines
6.3 KiB
TypeScript
189 lines
6.3 KiB
TypeScript
import { useState, useEffect } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import {
|
|
Dialog,
|
|
DialogContent,
|
|
DialogDescription,
|
|
DialogFooter,
|
|
DialogHeader,
|
|
DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from '@/components/ui/select';
|
|
import { User } from 'lucide-react';
|
|
import { userApi } from '@/api';
|
|
import type { JsonData } from '@/types/common';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
export interface UserFormData {
|
|
username: string;
|
|
nickname: string;
|
|
email: string;
|
|
phone: string;
|
|
role: string;
|
|
password: string;
|
|
status: number;
|
|
}
|
|
|
|
interface UserFormDialogProps {
|
|
open: boolean;
|
|
onOpenChange: (open: boolean) => void;
|
|
editingUser: JsonData | null;
|
|
form: UserFormData;
|
|
setForm: React.Dispatch<React.SetStateAction<UserFormData>>;
|
|
saving: boolean;
|
|
onSubmit: () => void;
|
|
}
|
|
|
|
export function UserFormDialog({
|
|
open,
|
|
onOpenChange,
|
|
editingUser,
|
|
form,
|
|
setForm,
|
|
saving,
|
|
onSubmit,
|
|
}: UserFormDialogProps) {
|
|
const { t } = useTranslation();
|
|
const [roles, setRoles] = useState<{ id: string; name: string }[]>([]);
|
|
|
|
// 对话框打开时拉取角色列表 // Logan.Li
|
|
useEffect(() => {
|
|
if (!open) return;
|
|
let cancelled = false;
|
|
(async () => {
|
|
try {
|
|
const resp = await userApi.getRoles();
|
|
if (cancelled) return;
|
|
const list = resp?.list ?? [];
|
|
setRoles(
|
|
list.map((r: JsonData) => ({
|
|
id: String(r.id ?? ''),
|
|
name: r.name ?? r.code ?? '',
|
|
}))
|
|
);
|
|
} catch {
|
|
if (!cancelled) setRoles([]);
|
|
}
|
|
})();
|
|
return () => {
|
|
cancelled = true;
|
|
};
|
|
}, [open]);
|
|
|
|
return (
|
|
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
<DialogContent className="dg-card">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
|
<User className="h-5 w-5 dg-text-blue" />
|
|
{editingUser ? t('system.editUser') : '新建用户'}
|
|
</DialogTitle>
|
|
<DialogDescription className="dg-text-muted">
|
|
{editingUser ? t('system.editUserDesc') : t('system.createUserDesc')}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
<div className="space-y-4">
|
|
<div className="grid grid-cols-2 gap-4">
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userName')}</label>
|
|
<Input
|
|
value={form.username}
|
|
onChange={(e) => setForm({ ...form, username: e.target.value })}
|
|
disabled={!!editingUser}
|
|
className="dg-input"
|
|
placeholder={t('system.loginUsername')}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userNickname')}</label>
|
|
<Input
|
|
value={form.nickname}
|
|
onChange={(e) => setForm({ ...form, nickname: e.target.value })}
|
|
className="dg-input"
|
|
placeholder={t('system.userShowNickname')}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userEmail')}</label>
|
|
<Input
|
|
value={form.email}
|
|
onChange={(e) => setForm({ ...form, email: e.target.value })}
|
|
className="dg-input"
|
|
placeholder="user@example.com"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userPhone')}</label>
|
|
<Input
|
|
value={form.phone}
|
|
onChange={(e) => setForm({ ...form, phone: e.target.value })}
|
|
className="dg-input"
|
|
placeholder={t('common.optional')}
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userRole')}</label>
|
|
<Select value={form.role} onValueChange={(v) => setForm({ ...form, role: v })}>
|
|
<SelectTrigger className="dg-input">
|
|
<SelectValue placeholder={t('deploy.rbac.selectRole')} />
|
|
</SelectTrigger>
|
|
<SelectContent className="dg-input">
|
|
{roles.map((role) => (
|
|
<SelectItem key={role.id} value={role.name}>
|
|
{role.name}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">{t('system.userStatus')}</label>
|
|
<Select
|
|
value={String(form.status)}
|
|
onValueChange={(v) => setForm({ ...form, status: Number(v) })}
|
|
>
|
|
<SelectTrigger className="dg-input">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent className="dg-input">
|
|
<SelectItem value="1">{t('common.normal')}</SelectItem>
|
|
<SelectItem value="0">{t('system.userInactive')}</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<label className="text-xs dg-text-muted">
|
|
密码{editingUser ? t('system.leaveBlankNoModify2') : ''}
|
|
</label>
|
|
<Input
|
|
type="password"
|
|
value={form.password}
|
|
onChange={(e) => setForm({ ...form, password: e.target.value })}
|
|
className="dg-input"
|
|
placeholder={editingUser ? t('system.passwordLeaveBlank') : t('system.setInitialPassword')}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]" onClick={() => onOpenChange(false)}>
|
|
{t('common.cancel')}
|
|
</Button>
|
|
<Button className="bg-blue-600 hover:bg-blue-700 text-white" onClick={onSubmit} disabled={saving}>
|
|
{saving ? t('k8s.topology.saving') : t('common.save')}
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
}
|