This commit is contained in:
2026-07-17 19:21:16 +08:00
parent a7d8bd25bb
commit e264214b77
+22 -17
View File
@@ -48,6 +48,7 @@ const LoginPage: React.FC = () => {
const [siteName, setSiteName] = useState(initialInfo.siteName); const [siteName, setSiteName] = useState(initialInfo.siteName);
const [siteLogo, setSiteLogo] = useState(initialInfo.siteLogo); const [siteLogo, setSiteLogo] = useState(initialInfo.siteLogo);
const [loginBgVideo, setLoginBgVideo] = useState(''); const [loginBgVideo, setLoginBgVideo] = useState('');
const [mediaReady, setMediaReady] = useState(false);
const [agreementPrivacyUrl, setAgreementPrivacyUrl] = useState(''); const [agreementPrivacyUrl, setAgreementPrivacyUrl] = useState('');
const [siteCopyright, setSiteCopyright] = useState(''); const [siteCopyright, setSiteCopyright] = useState('');
@@ -288,9 +289,12 @@ const LoginPage: React.FC = () => {
return ( return (
<div className="login-page"> <div className="login-page">
{/* 背景视频/动图全屏铺满 — 预加载避免闪烁 */} {/* 背景视频/动图全屏铺满 — 预加载完成后再显示页面 */}
<BackgroundVideo src={loginBgVideo} /> <BackgroundVideo src={loginBgVideo} onReady={() => setMediaReady(true)} />
<div className="login-bg-overlay" /> <div className="login-bg-overlay" style={{ opacity: mediaReady ? 1 : 0 }} />
{/* 内容区 — 媒体加载完成后淡入 */}
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', opacity: mediaReady ? 1 : 0, transition: 'opacity 0.5s ease', pointerEvents: mediaReady ? 'auto' : 'none' }}>
{/* 左上角 slogan */} {/* 左上角 slogan */}
<div className="login-slogan"> <div className="login-slogan">
@@ -498,32 +502,33 @@ const LoginPage: React.FC = () => {
</div> </div>
</div> </div>
)} )}
</div>{/* end media-ready wrapper */}
</div> </div>
); );
}; };
const BackgroundVideo: React.FC<{ src: string }> = ({ src }) => { const BackgroundVideo: React.FC<{ src: string; onReady: () => void }> = ({ src, onReady }) => {
const [ready, setReady] = useState(false); const [ready, setReady] = useState(false);
const vidRef = React.useRef<HTMLVideoElement>(null); const vidRef = React.useRef<HTMLVideoElement>(null);
if (!src) return null; const handleReady = () => {
if (ready) return;
setReady(true);
vidRef.current?.play().catch(() => {});
onReady();
};
if (!src) { onReady(); return null; }
const isGif = src.toLowerCase().endsWith('.gif'); const isGif = src.toLowerCase().endsWith('.gif');
const isWebp = src.toLowerCase().endsWith('.webp'); const isWebp = src.toLowerCase().endsWith('.webp');
if (isGif || isWebp) { if (isGif || isWebp) {
return <img className="login-bg-video" src={src} alt="" />; return <img className="login-bg-video" src={src} alt="" onLoad={handleReady} onError={handleReady} />;
} }
const handleCanPlay = () => {
setReady(true);
vidRef.current?.play().catch(() => {});
};
return ( return (
<>
{/* 视频加载前显示静态背景图作为占位 */}
{!ready && <div className="login-bg-video login-bg-poster" />}
<video <video
ref={vidRef} ref={vidRef}
className="login-bg-video" className="login-bg-video"
@@ -533,12 +538,12 @@ const BackgroundVideo: React.FC<{ src: string }> = ({ src }) => {
muted muted
playsInline playsInline
preload="auto" preload="auto"
onCanPlayThrough={handleCanPlay} onCanPlayThrough={handleReady}
onCanPlay={handleCanPlay} onCanPlay={handleReady}
onError={handleReady}
> >
<source src={src} type={src.endsWith('.webm') ? 'video/webm' : src.endsWith('.mov') ? 'video/quicktime' : 'video/mp4'} /> <source src={src} type={src.endsWith('.webm') ? 'video/webm' : src.endsWith('.mov') ? 'video/quicktime' : 'video/mp4'} />
</video> </video>
</>
); );
}; };