video-flow-b/components/QueueBox/queue-notification.tsx
2025-08-28 16:44:42 +08:00

210 lines
5.5 KiB
TypeScript

import { notification } from 'antd';
import { useRouter } from 'next/router';
type NotificationType = 'success' | 'info' | 'warning' | 'error';
const darkGlassStyle = {
background: 'rgba(30, 32, 40, 0.95)',
backdropFilter: 'blur(10px)',
WebkitBackdropFilter: 'blur(10px)',
border: '1px solid rgba(255, 255, 255, 0.08)',
borderRadius: '8px',
boxShadow: '0 4px 16px rgba(0, 0, 0, 0.4)',
padding: '12px 16px',
};
const messageStyle = {
fontSize: '13px',
fontWeight: 500,
color: '#ffffff',
marginBottom: '6px',
display: 'flex',
alignItems: 'center',
gap: '6px',
};
const iconStyle = {
color: '#F6B266', // 警告图标颜色
background: 'rgba(246, 178, 102, 0.15)',
padding: '4px',
borderRadius: '6px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
};
const descriptionStyle = {
fontSize: '12px',
color: 'rgba(255, 255, 255, 0.65)',
marginBottom: '12px',
lineHeight: '1.5',
};
const btnStyle = {
color: 'rgb(250 173 20 / 90%)',
background: 'transparent',
border: 'none',
cursor: 'pointer',
padding: 0,
fontSize: '12px',
fontWeight: 500,
textDecoration: 'underline',
textUnderlineOffset: '2px',
textDecorationColor: 'rgb(250 173 20 / 60%)',
transition: 'all 0.2s ease',
};
/** 场记板动画样式 */
const clapperboardStyle = {
position: 'relative' as const,
width: '40px',
height: '40px',
marginRight: '12px',
animation: 'clap 2s infinite',
};
/** 场记板文字样式 */
const sceneTextStyle = {
fontSize: '14px',
fontFamily: 'monospace',
color: '#F6B266',
marginBottom: '8px',
letterSpacing: '0.5px',
};
/** 队列信息样式 */
const queueInfoStyle = {
display: 'flex',
alignItems: 'center',
fontSize: '13px',
color: 'rgba(255, 255, 255, 0.9)',
marginBottom: '12px',
background: 'rgba(246, 178, 102, 0.1)',
padding: '8px 12px',
borderRadius: '6px',
};
/**
* 场记板SVG组件
*/
const Clapperboard = () => (
<div style={clapperboardStyle}>
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4 4H20V18C20 19.1046 19.1046 20 18 20H6C4.89543 20 4 19.1046 4 18V4Z"
stroke="#F6B266" strokeWidth="1.5"/>
<path d="M4 8H20" stroke="#F6B266" strokeWidth="1.5"/>
<path d="M9 4L11 8M15 4L17 8" stroke="#F6B266" strokeWidth="1.5"/>
<path className="clap-top" d="M4 4L20 4L17 8L4 8L4 4Z"
fill="rgba(246, 178, 102, 0.2)" stroke="#F6B266" strokeWidth="1.5"/>
</svg>
</div>
);
/**
* 显示队列等待通知
* @param position - 当前队列位置
* @param estimatedMinutes - 预计等待分钟数
*/
export const showQueueNotification = (position: number, estimatedMinutes: number) => {
// 生成场景号和镜次号
const sceneNumber = Math.floor(Math.random() * 5) + 1;
const takeNumber = Math.floor(Math.random() * 3) + 1;
notification.open({
message: null,
description: (
<div data-alt="queue-notification" style={{ minWidth: '320px' }}>
{/* 场记板和场景信息 */}
<div style={{ display: 'flex', alignItems: 'center', marginBottom: '12px' }}>
<Clapperboard />
<div>
<div style={sceneTextStyle}>
Scene {sceneNumber} - Take {takeNumber}
</div>
<div style={{ fontSize: '12px', color: 'rgba(255, 255, 255, 0.6)' }}>
AI Director's Cut
</div>
</div>
</div>
{/* 队列信息 */}
<div style={queueInfoStyle}>
<span style={{ marginRight: '8px' }}>🎬</span>
您的作品正在第 {position} 位等待制作
</div>
{/* 预计等待时间 */}
<div style={descriptionStyle}>
预计等待时间:约 {estimatedMinutes} 分钟
</div>
{/* 取消按钮 */}
<button
onClick={() => notification.destroy()}
style={{
...btnStyle,
marginTop: '8px',
}}
data-alt="cancel-queue-button"
>
取消制作 →
</button>
</div>
),
duration: 0, // 保持通知直到用户关闭
placement: 'topRight',
style: {
...darkGlassStyle,
border: '1px solid rgba(246, 178, 102, 0.2)',
},
className: 'movie-queue-notification',
closeIcon: (
<button
className="hover:text-white"
style={{
background: 'transparent',
border: 'none',
padding: '2px',
cursor: 'pointer',
color: 'rgba(255, 255, 255, 0.45)',
transition: 'color 0.2s ease',
}}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M18 6L6 18M6 6L18 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
</svg>
</button>
),
});
};
// 添加必要的CSS动画
const styles = `
@keyframes clap {
0%, 100% { transform: rotate(0deg); }
5% { transform: rotate(-15deg); }
10% { transform: rotate(0deg); }
}
.movie-queue-notification {
animation: slideIn 0.3s ease-out;
}
@keyframes slideIn {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
`;
// 将样式注入到页面
if (typeof document !== 'undefined') {
const styleSheet = document.createElement('style');
styleSheet.textContent = styles;
document.head.appendChild(styleSheet);
}
// 保持现有的notification配置
notification.config({
maxCount: 3,
});