flnxi-Wu/components/ui/ActivationModal.tsx
2026-05-28 18:46:07 +08:00

156 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useState } from 'react';
import { cn } from '@/lib/ui-styles';
interface ActivationModalProps {
isOpen: boolean;
onClose: () => void;
onSuccess?: () => void;
}
export default function ActivationModal({ isOpen, onClose, onSuccess }: ActivationModalProps) {
const [activationCode, setActivationCode] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
if (!isOpen) return null;
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
setError(null);
const code = activationCode.trim().toUpperCase();
if (!code) {
setError('请输入激活码');
return;
}
// 简单格式验证
if (!code.startsWith('FLNXI-')) {
setError('激活码格式不正确');
return;
}
setLoading(true);
try {
const response = await fetch('/api/license/activate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ activationCode: code }),
});
const data = await response.json();
if (data.success) {
onSuccess?.();
onClose();
// 刷新页面以更新许可证状态
window.location.reload();
} else {
setError(data.error || '激活失败,请检查激活码是否正确');
}
} catch (err) {
setError('网络错误,请稍后重试');
} finally {
setLoading(false);
}
};
return (
<div className="fixed inset-0 z-50 flex items-center justify-center">
{/* 背景遮罩 */}
<div
className="absolute inset-0 bg-black/45"
onClick={onClose}
/>
{/* 弹窗内容 */}
<div className="relative bg-white dark:bg-slate-800 rounded-lg shadow-sm border border-slate-200 dark:border-slate-700 w-full max-w-md mx-4 overflow-hidden">
{/* 头部 */}
<div className="px-6 py-4 border-b border-slate-200 dark:border-slate-700">
<div className="flex items-center justify-between">
<h3 className="text-lg font-semibold text-slate-900 dark:text-white">
激活许可证
</h3>
<button
onClick={onClose}
className="p-1 rounded-lg hover:bg-slate-100 dark:hover:bg-slate-700 transition-colors"
>
<svg className="w-5 h-5 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
{/* 内容 */}
<form onSubmit={handleSubmit} className="p-6 space-y-4">
<div>
<label className="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
激活码
</label>
<input
type="text"
value={activationCode}
onChange={(e) => setActivationCode(e.target.value.toUpperCase())}
placeholder="FLNXI-PRO-XXXX-XXXX-XXXX-XXXX"
className={cn(
'w-full px-4 py-3 rounded-lg border text-sm font-mono',
'bg-slate-50 dark:bg-slate-900',
'border-slate-200 dark:border-slate-700',
'text-slate-900 dark:text-white',
'placeholder:text-slate-400 dark:placeholder:text-slate-500',
'focus:outline-none focus:ring-2 focus:ring-slate-200 dark:focus:ring-slate-700 focus:border-slate-900 dark:focus:border-slate-500',
'transition-colors'
)}
autoFocus
/>
<p className="mt-2 text-xs text-slate-500 dark:text-slate-400">
激活码格式:FLNXI-PRO-XXXX-XXXX-XXXX-XXXX
</p>
</div>
{error && (
<div className="px-4 py-3 rounded-lg bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800">
<p className="text-sm text-red-600 dark:text-red-400">{error}</p>
</div>
)}
<div className="flex gap-3">
<button
type="submit"
disabled={loading}
className={cn(
'flex-1 px-4 py-3 rounded-lg font-medium text-sm transition-colors',
'bg-slate-900 dark:bg-slate-100 text-white dark:text-slate-900 hover:bg-slate-800 dark:hover:bg-white',
'disabled:opacity-50 disabled:cursor-not-allowed'
)}
>
{loading ? (
<span className="flex items-center justify-center gap-2">
<svg className="w-4 h-4 animate-spin" viewBox="0 0 24 24" fill="none">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
</svg>
激活中...
</span>
) : (
'立即激活'
)}
</button>
</div>
</form>
{/* 底部 */}
<div className="px-6 py-4 bg-slate-50 dark:bg-slate-900/50 border-t border-slate-200 dark:border-slate-700">
<p className="text-sm text-slate-500 dark:text-slate-400">
如需许可证,请联系系统交付人员或管理员。
</p>
</div>
</div>
</div>
);
}