forked from 77media/video-flow
210 lines
5.5 KiB
TypeScript
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,
|
|
});
|