123 lines
4.2 KiB
TypeScript
123 lines
4.2 KiB
TypeScript
'use client';
|
||
|
||
import { AlertTriangle } from 'lucide-react';
|
||
import { useEffect, useState } from 'react';
|
||
import { createPortal } from 'react-dom';
|
||
import { getAuthInfoFromBrowserCookie } from '@/lib/auth';
|
||
|
||
interface HttpWarningDialogProps {
|
||
onClose: () => void;
|
||
}
|
||
|
||
export default function HttpWarningDialog({ onClose }: HttpWarningDialogProps) {
|
||
const [isVisible, setIsVisible] = useState(false);
|
||
const [shouldShow, setShouldShow] = useState(false);
|
||
|
||
useEffect(() => {
|
||
// 检查是否应该显示弹窗
|
||
const checkShouldShow = () => {
|
||
// 只在客户端执行
|
||
if (typeof window === 'undefined') return false;
|
||
|
||
// 检查是否已经选择不再提示
|
||
const dontShowAgain = localStorage.getItem('httpWarningDismissed');
|
||
if (dontShowAgain === 'true') return false;
|
||
|
||
// 检查是否是站长
|
||
const authInfo = getAuthInfoFromBrowserCookie();
|
||
if (!authInfo || authInfo.role !== 'owner') return false;
|
||
|
||
// 检查是否是 HTTP 环境(非 localhost 和 127.0.0.1)
|
||
const { protocol, hostname } = window.location;
|
||
const isHttp = protocol === 'http:';
|
||
const isLocalhost = hostname === 'localhost' || hostname === '127.0.0.1';
|
||
|
||
// 只在 HTTP 且非本地环境下显示
|
||
return isHttp && !isLocalhost;
|
||
};
|
||
|
||
const shouldDisplay = checkShouldShow();
|
||
setShouldShow(shouldDisplay);
|
||
|
||
if (shouldDisplay) {
|
||
// 延迟显示动画
|
||
setTimeout(() => setIsVisible(true), 100);
|
||
}
|
||
}, []);
|
||
|
||
const handleDontShowAgain = () => {
|
||
localStorage.setItem('httpWarningDismissed', 'true');
|
||
handleClose();
|
||
};
|
||
|
||
const handleClose = () => {
|
||
setIsVisible(false);
|
||
setTimeout(() => {
|
||
onClose();
|
||
}, 300);
|
||
};
|
||
|
||
// 如果不需要显示,直接返回 null
|
||
if (!shouldShow) return null;
|
||
|
||
return createPortal(
|
||
<div
|
||
className={`fixed inset-0 bg-black bg-opacity-50 z-[9999] flex items-center justify-center p-4 transition-opacity duration-300 ${
|
||
isVisible ? 'opacity-100' : 'opacity-0'
|
||
}`}
|
||
onClick={handleClose}
|
||
>
|
||
<div
|
||
className={`bg-white dark:bg-gray-800 rounded-lg shadow-xl max-w-md w-full border border-yellow-200 dark:border-yellow-800 transition-all duration-300 ${
|
||
isVisible ? 'scale-100' : 'scale-95'
|
||
}`}
|
||
onClick={(e) => e.stopPropagation()}
|
||
>
|
||
<div className="p-6">
|
||
{/* 图标和标题 */}
|
||
<div className="flex items-start gap-4 mb-4">
|
||
<div className="flex-shrink-0">
|
||
<AlertTriangle className="w-8 h-8 text-yellow-500" />
|
||
</div>
|
||
<div className="flex-1">
|
||
<h3 className="text-lg font-semibold text-gray-900 dark:text-gray-100 mb-2">
|
||
HTTP 环境功能限制提示
|
||
</h3>
|
||
<div className="text-sm text-gray-600 dark:text-gray-400 space-y-2">
|
||
<p>
|
||
检测到您正在使用 HTTP 协议访问本站。由于浏览器安全策略限制,以下功能将无法正常使用:
|
||
</p>
|
||
<ul className="list-disc list-inside space-y-1 ml-2">
|
||
<li>视频超分(AI 画质增强)</li>
|
||
<li>麦克风语音功能</li>
|
||
<li>其他需要安全上下文的高级功能</li>
|
||
</ul>
|
||
<p className="mt-3 text-yellow-600 dark:text-yellow-500 font-medium">
|
||
建议配置 HTTPS 证书以获得完整功能体验。
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{/* 按钮组 */}
|
||
<div className="flex gap-3 mt-6">
|
||
<button
|
||
onClick={handleDontShowAgain}
|
||
className="flex-1 px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg transition-colors"
|
||
>
|
||
不再提示
|
||
</button>
|
||
<button
|
||
onClick={handleClose}
|
||
className="flex-1 px-4 py-2 text-sm font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors"
|
||
>
|
||
我知道了
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>,
|
||
document.body
|
||
);
|
||
}
|