批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换: - 翻译词典: 22 namespaces, 3600+ keys - 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy) - 语言切换器在 Header 中可用 (🇨🇳/🇺🇸) - tsc 零错误, Vite 构建成功
97 lines
3.8 KiB
TypeScript
97 lines
3.8 KiB
TypeScript
// 管理员重置用户密码弹窗 // Logan.Li
|
|
import { useState } from 'react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import {
|
|
Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle,
|
|
} from '@/components/ui/dialog';
|
|
import { Key, Loader2 } from 'lucide-react';
|
|
import { useToast } from '@/hooks/use-toast';
|
|
import { userApi } from '@/api';
|
|
import { useTranslation } from 'react-i18next';
|
|
|
|
interface ResetPasswordDialogProps {
|
|
user: { id: number | string; username?: string; nickname?: string; authSource?: string } | null;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export function ResetPasswordDialog({ user, onClose }: ResetPasswordDialogProps) {
|
|
const { t } = useTranslation();
|
|
const { toast } = useToast();
|
|
const [password, setPassword] = useState('');
|
|
const [confirm, setConfirm] = useState('');
|
|
const [saving, setSaving] = useState(false);
|
|
|
|
const isLdap = user?.authSource === 'ldap';
|
|
const canSubmit = password.length >= 6 && password === confirm && !isLdap;
|
|
|
|
const handleReset = async () => {
|
|
if (!user || !canSubmit) return;
|
|
setSaving(true);
|
|
try {
|
|
await userApi.resetUserPassword(user.id, password);
|
|
toast({ title: t('system.passwordReset'), description: `用户 ${user.nickname || user.username} 的新密码已生效` });
|
|
setPassword('');
|
|
setConfirm('');
|
|
onClose();
|
|
} catch (e: any) {
|
|
toast({ title: t('system.resetFailed'), description: e?.message || String(e), variant: 'destructive' });
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Dialog open={!!user} onOpenChange={(open) => { if (!open) { setPassword(''); setConfirm(''); onClose(); } }}>
|
|
<DialogContent className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)] sm:max-w-md">
|
|
<DialogHeader>
|
|
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
|
<Key className="h-5 w-5 text-[var(--dg-blue)]" />
|
|
{t('system.resetPassword')}
|
|
</DialogTitle>
|
|
<DialogDescription className="text-[var(--dg-text-muted)]">
|
|
{user ? `为「${user.nickname || user.username}」设置新密码` : ''}
|
|
</DialogDescription>
|
|
</DialogHeader>
|
|
|
|
{isLdap ? (
|
|
<p className="text-sm dg-text-yellow/90 py-2">{t('system.ldapResetHint')}</p>
|
|
) : (
|
|
<div className="space-y-3 py-1">
|
|
<div>
|
|
<Label className="text-xs text-[var(--dg-text-muted)]">{t('system.newPassword')}</Label>
|
|
<Input
|
|
type="password"
|
|
value={password}
|
|
onChange={e => setPassword(e.target.value)}
|
|
placeholder={t('system.passwordMinLen')}
|
|
className="mt-1 h-9 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)]"
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label className="text-xs text-[var(--dg-text-muted)]">{t('system.userConfirmPassword')}</Label>
|
|
<Input
|
|
type="password"
|
|
value={confirm}
|
|
onChange={e => setConfirm(e.target.value)}
|
|
placeholder={t('system.confirmNewPassword')}
|
|
className="mt-1 h-9 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)]"
|
|
/>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<DialogFooter>
|
|
<Button variant="outline" className="border-[var(--dg-border)]" onClick={onClose}>{t('common.cancel')}</Button>
|
|
{!isLdap && (
|
|
<Button onClick={handleReset} disabled={!canSubmit || saving} className="bg-[var(--dg-blue)] hover:opacity-90">
|
|
{saving ? <Loader2 className="h-4 w-4 animate-spin mr-1" /> : null}
|
|
确认重置
|
|
</Button>
|
|
)}
|
|
</DialogFooter>
|
|
</DialogContent>
|
|
</Dialog>
|
|
);
|
|
} |