1416 lines
74 KiB
TypeScript
1416 lines
74 KiB
TypeScript
import React, { useEffect, useState, useRef } from 'react';
|
|
import { Button, Input, Tabs, Tag, Upload, message, Modal } from 'antd';
|
|
import {
|
|
FileTextOutlined,
|
|
ScissorOutlined,
|
|
RobotOutlined,
|
|
ArrowRightOutlined,
|
|
UploadOutlined,
|
|
VideoCameraOutlined,
|
|
PictureOutlined,
|
|
AudioOutlined,
|
|
PauseOutlined,
|
|
ThunderboltOutlined,
|
|
PlayCircleOutlined,
|
|
HeartOutlined,
|
|
ShareAltOutlined,
|
|
StarOutlined,
|
|
CopyOutlined,
|
|
} from '@ant-design/icons';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { getmedit ,getHomeCaseHeader,getHomeCaseButton} from '../api';
|
|
|
|
|
|
|
|
|
|
interface CaseAssetCardProps {
|
|
asset: any;
|
|
index: number;
|
|
onPreview: (asset: any) => void;
|
|
}
|
|
|
|
const CaseAssetCard: React.FC<CaseAssetCardProps> = ({ asset, index, onPreview }) => {
|
|
const [isHovered, setIsHovered] = useState(false);
|
|
|
|
return (
|
|
<div
|
|
className="project-card"
|
|
onClick={() => onPreview(asset)}
|
|
onMouseEnter={() => setIsHovered(true)}
|
|
onMouseLeave={() => setIsHovered(false)}
|
|
style={{
|
|
borderRadius: 12,
|
|
overflow: 'hidden',
|
|
cursor: 'pointer',
|
|
flexShrink: 0,
|
|
width: "18%",
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<div style={{ position: 'relative', aspectRatio: '9/16', }}>
|
|
{asset.mediaType === 'video' ? (
|
|
<>
|
|
<video
|
|
src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${asset.url}`}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
muted
|
|
playsInline
|
|
/>
|
|
<div style={{
|
|
position: 'absolute',
|
|
inset: 0,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}>
|
|
<div style={{
|
|
width: 40,
|
|
height: 40,
|
|
borderRadius: '50%',
|
|
background: 'rgba(0,0,0,0.5)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
}}>
|
|
<PlayCircleOutlined style={{ fontSize: 24, color: '#fff' }} />
|
|
</div>
|
|
</div>
|
|
</>
|
|
) : (
|
|
<img
|
|
src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${asset.url}`}
|
|
alt={asset.title || `素材 ${index + 1}`}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
)}
|
|
{/* <div
|
|
style={{
|
|
position: 'absolute',
|
|
inset: 0,
|
|
background: 'rgba(0,0,0,0.6)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
opacity: isHovered ? 1 : 0,
|
|
transition: 'opacity 0.4s ease',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
alignItems: 'center',
|
|
gap: 10,
|
|
padding: '24px 36px',
|
|
background: 'linear-gradient(135deg, rgba(6,182,212,0.2), rgba(99,102,241,0.2))',
|
|
borderRadius: 16,
|
|
backdropFilter: 'blur(20px)',
|
|
border: '1px solid rgba(6,182,212,0.3)',
|
|
boxShadow: isHovered ? '0 0 30px rgba(6,182,212,0.4), 0 0 60px rgba(99,102,241,0.2)' : 'none',
|
|
transform: isHovered ? 'scale(1) translateY(0)' : 'scale(0.95) translateY(10px)',
|
|
transition: 'transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.4s ease',
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
position: 'relative',
|
|
width: 56,
|
|
height: 56,
|
|
borderRadius: '50%',
|
|
background: 'linear-gradient(135deg, #06b6d4, #6366f1)',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
animation: isHovered ? 'pulse-glow 2s ease-in-out infinite' : 'none',
|
|
}}
|
|
>
|
|
<CopyOutlined style={{ fontSize: 28, color: '#fff' }} />
|
|
<div
|
|
style={{
|
|
position: 'absolute',
|
|
inset: '-4px',
|
|
borderRadius: '50%',
|
|
background: 'linear-gradient(135deg, #06b6d4, #6366f1)',
|
|
opacity: 0.3,
|
|
animation: isHovered ? 'ripple 2s ease-out infinite' : 'none',
|
|
}}
|
|
/>
|
|
</div>
|
|
<span
|
|
style={{
|
|
fontSize: 14,
|
|
color: '#fff',
|
|
fontWeight: 600,
|
|
letterSpacing: 1,
|
|
textShadow: '0 0 10px rgba(6,182,212,0.5)',
|
|
}}
|
|
>
|
|
点击预览
|
|
</span>
|
|
<style>{`
|
|
@keyframes pulse-glow {
|
|
0%, 100% { box-shadow: 0 0 20px rgba(6,182,212,0.5); }
|
|
50% { box-shadow: 0 0 40px rgba(99,102,241,0.6), 0 0 60px rgba(6,182,212,0.3); }
|
|
}
|
|
@keyframes ripple {
|
|
0% { transform: scale(1); opacity: 0.6; }
|
|
100% { transform: scale(1.8); opacity: 0; }
|
|
}
|
|
`}</style>
|
|
</div>
|
|
</div> */}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
// 把 ISO 时间格式化成 MM-DD HH:mm(与图片一致)
|
|
function formatShortDate(iso?: string | null): string {
|
|
if (!iso) return '-';
|
|
let s = String(iso).trim();
|
|
if (!s.includes('T')) s = s.replace(' ', 'T');
|
|
const dotIdx = s.indexOf('.');
|
|
if (dotIdx > 0) s = s.slice(0, dotIdx);
|
|
s = s.replace(/[+-]\d{2}:?\d{0,2}$/, '').replace(/Z$/, '');
|
|
// s 形如 2026-06-18T17:17:00
|
|
const [datePart = '', timePart = ''] = s.split('T');
|
|
const [, month = '', day = ''] = datePart.split('-');
|
|
const hhmm = timePart.slice(0, 5);
|
|
if (!month || !day) return '-';
|
|
return `${month}-${day} ${hhmm}`;
|
|
}
|
|
|
|
const HomePage: React.FC = () => {
|
|
const navigate = useNavigate();
|
|
const [activeTab, setActiveTab] = useState('project');
|
|
const [inputValue, setInputValue] = useState('');
|
|
const [mockVideos, setMockVideos] = useState<any[]>([]);
|
|
const [caseHeader, setCaseHeader] = useState<any[]>([]);
|
|
const [activeCaseTab, setActiveCaseTab] = useState<string>('');
|
|
const [caseAssets, setCaseAssets] = useState<any[]>([]);
|
|
const [previewAsset, setPreviewAsset] = useState<any>(null);
|
|
const [aspectRatio, setAspectRatio] = useState<string>('');
|
|
const previewVideoRef = useRef<HTMLVideoElement>(null);
|
|
const currentAssetIdRef = useRef<string>('');
|
|
const [activeContentTab, setActiveContentTab] = useState<'works' | 'cases'>('cases');
|
|
const [playingVideoIndex, setPlayingVideoIndex] = useState<number | null>(null);
|
|
const [playingAudioUrl, setPlayingAudioUrl] = useState<string | null>(null);
|
|
const audioRef = useRef<HTMLAudioElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
getHomeCaseHeader().then((res: any) => {
|
|
// console.log('caseHeader:', res);
|
|
if (res?.items?.length > 0) {
|
|
setCaseHeader(res.items);
|
|
const firstId = res.items[0].id;
|
|
setActiveCaseTab(firstId);
|
|
// 初始请求第一个 tab 的数据
|
|
getHomeCaseButton(firstId).then((btnRes: any) => {
|
|
// console.log('caseButton:', btnRes);
|
|
if (btnRes?.categories?.[0]?.assets) {
|
|
setCaseAssets(btnRes.categories[0].assets);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
return () => {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause();
|
|
audioRef.current = null;
|
|
}
|
|
setPlayingAudioUrl(null);
|
|
setPlayingVideoIndex(null);
|
|
const allVideos = document.querySelectorAll('.preview-video-item');
|
|
allVideos.forEach((v) => {
|
|
(v as HTMLVideoElement).pause();
|
|
});
|
|
};
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!previewAsset) {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause();
|
|
audioRef.current = null;
|
|
}
|
|
setPlayingAudioUrl(null);
|
|
setPlayingVideoIndex(null);
|
|
setAspectRatio('');
|
|
currentAssetIdRef.current = '';
|
|
const allVideos = document.querySelectorAll('.preview-video-item');
|
|
allVideos.forEach((v) => {
|
|
(v as HTMLVideoElement).pause();
|
|
});
|
|
return;
|
|
}
|
|
|
|
const assetId = previewAsset.id || previewAsset.url;
|
|
currentAssetIdRef.current = assetId;
|
|
|
|
const gcd = (a: number, b: number): number => b === 0 ? a : gcd(b, a % b);
|
|
|
|
const width = previewAsset.width || previewAsset.videoWidth || previewAsset.imageWidth || 0;
|
|
const height = previewAsset.height || previewAsset.videoHeight || previewAsset.imageHeight || 0;
|
|
|
|
if (width && height) {
|
|
const divisor = gcd(width, height);
|
|
setAspectRatio(`${width / divisor}:${height / divisor}`);
|
|
return;
|
|
}
|
|
|
|
setAspectRatio('');
|
|
|
|
if (previewAsset.mediaType === 'video') {
|
|
const video = previewVideoRef.current;
|
|
const handleLoadedMetadata = () => {
|
|
if (currentAssetIdRef.current !== assetId) return;
|
|
const w = video!.videoWidth;
|
|
const h = video!.videoHeight;
|
|
if (!w || !h) return;
|
|
const divisor = gcd(w, h);
|
|
setAspectRatio(`${w / divisor}:${h / divisor}`);
|
|
};
|
|
|
|
video?.removeEventListener('loadedmetadata', handleLoadedMetadata);
|
|
|
|
if (video && video.videoWidth && video.videoHeight) {
|
|
const divisor = gcd(video.videoWidth, video.videoHeight);
|
|
setAspectRatio(`${video.videoWidth / divisor}:${video.videoHeight / divisor}`);
|
|
} else {
|
|
video?.addEventListener('loadedmetadata', handleLoadedMetadata);
|
|
}
|
|
|
|
return () => {
|
|
video?.removeEventListener('loadedmetadata', handleLoadedMetadata);
|
|
};
|
|
} else {
|
|
const img = new Image();
|
|
img.crossOrigin = 'anonymous';
|
|
img.onload = () => {
|
|
if (currentAssetIdRef.current !== assetId) return;
|
|
const w = img.width;
|
|
const h = img.height;
|
|
if (!w || !h) {
|
|
setAspectRatio('未知');
|
|
return;
|
|
}
|
|
const divisor = gcd(w, h);
|
|
setAspectRatio(`${w / divisor}:${h / divisor}`);
|
|
};
|
|
img.onerror = () => {
|
|
if (currentAssetIdRef.current !== assetId) return;
|
|
setAspectRatio('未知');
|
|
};
|
|
img.src = `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewAsset.url}`;
|
|
}
|
|
}, [previewAsset]);
|
|
|
|
useEffect(() => {
|
|
const fetchAll = async () => {
|
|
try {
|
|
|
|
getmedit(10).then((res) => {
|
|
for (let item in res) {
|
|
res[item].forEach(element => {
|
|
// 给每条 element 标记它所属的模块(item 是接口返回的 key)
|
|
element.type = item;
|
|
// 依次追加到 mockVideos(函数式更新,保证拿到最新 state)
|
|
setMockVideos(prev => [...prev, element]);
|
|
});
|
|
}
|
|
// 最终再打印一次汇总(state 异步更新,这里打印的是本次追加的累计长度)
|
|
setMockVideos(prev => {
|
|
return prev;
|
|
});
|
|
});
|
|
|
|
} catch (err) {
|
|
}
|
|
};
|
|
fetchAll();
|
|
}, []);
|
|
|
|
const handleTabChange = (key: string) => {
|
|
setActiveTab(key);
|
|
};
|
|
|
|
|
|
|
|
const aiEntries = [
|
|
{
|
|
icon: <FileTextOutlined style={{ fontSize: 24 }} />,
|
|
title: '行业智造',
|
|
description: '新建项目、设置图文视频参数、核对信息并生成素材',
|
|
action: '立即创作',
|
|
path: '/projects',
|
|
},
|
|
{
|
|
icon: <RobotOutlined style={{ fontSize: 24 }} />,
|
|
title: 'AI成片',
|
|
description: '输入想法、剧本或上传参考,智能生成视频/图片',
|
|
action: '立即生成',
|
|
path: '/conversation',
|
|
},
|
|
{
|
|
icon: <FileTextOutlined style={{ fontSize: 24 }} />,
|
|
title: '爆款复刻',
|
|
description: '上传参考视频与产品图片,一键复刻爆款',
|
|
action: '立即创作',
|
|
path: '/initial',
|
|
},
|
|
{
|
|
icon: <ScissorOutlined style={{ fontSize: 24 }} />,
|
|
title: '拆镜复刻',
|
|
description: '精细化镜头复刻工具,拆分参考视频单镜头独立复刻,提升素材原创度,规避素材同质化',
|
|
action: '开始拆镜',
|
|
path: '/removelens',
|
|
},
|
|
|
|
|
|
];
|
|
|
|
const tabs = [
|
|
{ key: 'all', label: '全部' },
|
|
{ key: 'project', label: '项目媒体' },
|
|
{ key: 'chatAi', label: 'AI成片' },
|
|
{ key: 'hotOpeningReplicate', label: '爆款复刻' },
|
|
{ key: 'shotReplicate', label: '拆镜复刻' },
|
|
];
|
|
|
|
const filteredVideos = activeTab === 'all'
|
|
? mockVideos
|
|
: mockVideos.filter(v => v.type === activeTab);
|
|
|
|
|
|
return (
|
|
<div className="content_box">
|
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 16 }}>
|
|
<h3>首页工作台 </h3>
|
|
<p
|
|
style={{
|
|
cursor: 'pointer',
|
|
fontSize: 12, letterSpacing: 0.3,
|
|
padding: '10px 16px',
|
|
backgroundColor: '#ffffffff',
|
|
borderRadius: 30,
|
|
boxShadow: '0px 4px 12px 0px rgba(0, 0, 0, 0.1)',
|
|
|
|
}}
|
|
|
|
>如需进行账户素材推送:
|
|
<span
|
|
style={{
|
|
color: '#1a50bbff',
|
|
|
|
}}
|
|
onClick={() => {
|
|
navigate('/authorization')
|
|
}}>
|
|
一键推送
|
|
<ArrowRightOutlined style={{ marginLeft: 8, transform: 'rotate(0deg)' }} />
|
|
</span>
|
|
|
|
|
|
</p>
|
|
</div>
|
|
{/* ========== 顶部工作台引导区域(三步流程) ========== */}
|
|
{/* <div className="animate-fadeInUp" style={{
|
|
padding: '24px 28px',
|
|
borderRadius: 16,
|
|
background: 'linear-gradient(135deg, #f0f9ff 0%, #faf5ff 50%, #fef3c7 100%)',
|
|
border: '1px solid rgba(99,102,241,0.10)',
|
|
margin: '0 0 20px',
|
|
position: 'relative',
|
|
overflow: 'hidden',
|
|
}}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 18 }}>
|
|
<div>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
<div style={{
|
|
width: 4, height: 18, borderRadius: 2,
|
|
background: 'linear-gradient(180deg, #6366f1, #a855f7)',
|
|
}} />
|
|
<div style={{ fontSize: 17, fontWeight: 700, color: '#1f2937', letterSpacing: 0.3 }}>
|
|
我的项目<span style={{ color: '#a8a8a8ff', fontSize: 12 }}>(操作步骤)</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 12,
|
|
}}>
|
|
<div style={{
|
|
flex: 1,
|
|
background: '#fff',
|
|
borderRadius: 14,
|
|
padding: '20px 18px',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
boxShadow: '0 2px 8px rgba(15, 23, 42, 0.04)',
|
|
}}>
|
|
<div style={{ textAlign: 'center', fontSize: 20, fontWeight: 700, color: '#1e293b', marginBottom: 14, letterSpacing: 1 }}>
|
|
第1步
|
|
</div>
|
|
<div style={{
|
|
flex: 1,
|
|
minHeight: 140,
|
|
border: '1px dashed #c7d2fe',
|
|
borderRadius: 8,
|
|
background: '#fafbff',
|
|
padding: 10,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: 8,
|
|
marginBottom: 12,
|
|
}}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
<div style={{ width: 8, height: 8, borderRadius: 2, background: '#6366f1' }} />
|
|
<div style={{ flex: 1, height: 22, background: '#fff', border: '1px solid #e2e8f0', borderRadius: 4, display: 'flex', alignItems: 'center', padding: '0 8px', fontSize: 10, color: '#94a3b8' }}>
|
|
项目名称...
|
|
</div>
|
|
</div>
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
|
|
<div style={{ padding: '2px 8px', background: '#eef2ff', color: '#6366f1', borderRadius: 10, fontSize: 10, fontWeight: 500, border: '1px solid #c7d2fe' }}>美妆</div>
|
|
<div style={{ padding: '2px 8px', background: '#fff7ed', color: '#f97316', borderRadius: 10, fontSize: 10, fontWeight: 500, border: '1px solid #fed7aa' }}>美食</div>
|
|
<div style={{ padding: '2px 8px', background: '#ecfdf5', color: '#10b981', borderRadius: 10, fontSize: 10, fontWeight: 500, border: '1px solid #a7f3d0' }}>3C数码</div>
|
|
<div style={{ padding: '2px 8px', background: '#f5f3ff', color: '#8b5cf6', borderRadius: 10, fontSize: 10, fontWeight: 500, border: '1px solid #ddd6fe' }}>服饰</div>
|
|
</div>
|
|
<div style={{ height: 16, background: '#fff', border: '1px solid #e2e8f0', borderRadius: 4 }} />
|
|
<div style={{ height: 16, width: '70%', background: '#fff', border: '1px solid #e2e8f0', borderRadius: 4 }} />
|
|
</div>
|
|
<div style={{
|
|
background: '#f1f5f9',
|
|
borderRadius: 10,
|
|
padding: '14px 12px',
|
|
textAlign: 'center',
|
|
fontSize: 13,
|
|
color: '#475569',
|
|
lineHeight: 1.6,
|
|
}}>
|
|
创建新项目,自定义项目名称并选择对应行业分类
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', color: '#94a3b8', fontSize: 22 }}>
|
|
<ArrowRightOutlined style={{ transform: 'rotate(0deg)' }} />
|
|
</div>
|
|
|
|
<div style={{
|
|
flex: 1,
|
|
background: '#fff',
|
|
borderRadius: 14,
|
|
padding: '20px 18px',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
boxShadow: '0 2px 8px rgba(15, 23, 42, 0.04)',
|
|
}}>
|
|
<div style={{ textAlign: 'center', fontSize: 20, fontWeight: 700, color: '#1e293b', marginBottom: 14, letterSpacing: 1 }}>
|
|
第2步
|
|
</div>
|
|
<div style={{
|
|
flex: 1,
|
|
minHeight: 140,
|
|
border: '1px solid #e2e8f0',
|
|
borderRadius: 8,
|
|
background: '#fafafa',
|
|
padding: 10,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: 8,
|
|
marginBottom: 12,
|
|
}}>
|
|
<div style={{ display: 'flex', background: '#f1f5f9', borderRadius: 6, padding: 2, gap: 2 }}>
|
|
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4, padding: '5px 0', background: '#fff', borderRadius: 4, fontSize: 11, fontWeight: 600, color: '#6366f1', boxShadow: '0 1px 3px rgba(99,102,241,0.15)' }}>
|
|
<VideoCameraOutlined style={{ fontSize: 11 }} />视频
|
|
</div>
|
|
<div style={{ flex: 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 4, padding: '5px 0', fontSize: 11, color: '#94a3b8' }}>
|
|
<PictureOutlined style={{ fontSize: 11 }} /> 图片
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 9, color: '#94a3b8', marginBottom: 3 }}>尺寸比例</div>
|
|
<div style={{ display: 'flex', gap: 4 }}>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#eef2ff', color: '#6366f1', border: '1px solid #c7d2fe', borderRadius: 4, fontSize: 10, fontWeight: 600 }}>9:16</div>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#fff', color: '#64748b', border: '1px solid #e2e8f0', borderRadius: 4, fontSize: 10 }}>16:9</div>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#fff', color: '#64748b', border: '1px solid #e2e8f0', borderRadius: 4, fontSize: 10 }}>1:1</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div style={{ fontSize: 9, color: '#94a3b8', marginBottom: 3 }}>时长</div>
|
|
<div style={{ display: 'flex', gap: 4 }}>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#fff', color: '#64748b', border: '1px solid #e2e8f0', borderRadius: 4, fontSize: 10 }}>5s</div>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#fff7ed', color: '#f97316', border: '1px solid #fed7aa', borderRadius: 4, fontSize: 10, fontWeight: 600 }}>10s</div>
|
|
<div style={{ flex: 1, textAlign: 'center', padding: '4px 0', background: '#fff', color: '#64748b', border: '1px solid #e2e8f0', borderRadius: 4, fontSize: 10 }}>15s</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div style={{
|
|
background: '#f1f5f9',
|
|
borderRadius: 10,
|
|
padding: '14px 12px',
|
|
textAlign: 'center',
|
|
fontSize: 13,
|
|
color: '#475569',
|
|
lineHeight: 1.6,
|
|
}}>
|
|
选择生成图片或视频,设置尺寸、时长等参数,点击生成即可一键优化提示词
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', alignItems: 'center', color: '#94a3b8', fontSize: 22 }}>
|
|
<ArrowRightOutlined />
|
|
</div>
|
|
|
|
<div style={{
|
|
flex: 1,
|
|
background: '#fff',
|
|
borderRadius: 14,
|
|
padding: '20px 18px',
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
boxShadow: '0 2px 8px rgba(15, 23, 42, 0.04)',
|
|
}}>
|
|
<div style={{ textAlign: 'center', fontSize: 20, fontWeight: 700, color: '#1e293b', marginBottom: 14, letterSpacing: 1 }}>
|
|
第3步
|
|
</div>
|
|
<div style={{
|
|
flex: 1,
|
|
minHeight: 140,
|
|
border: '1px solid #e2e8f0',
|
|
borderRadius: 8,
|
|
background: '#fafafa',
|
|
padding: 10,
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
gap: 6,
|
|
marginBottom: 12,
|
|
justifyContent: 'space-between',
|
|
}}>
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 8px', background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: 5 }}>
|
|
<div style={{ width: 14, height: 14, borderRadius: '50%', background: '#10b981', color: '#fff', fontSize: 10, display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700 }}>✓</div>
|
|
<div style={{ fontSize: 10, color: '#065f46', fontWeight: 500 }}>提示词已智能优化</div>
|
|
</div>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6, padding: '5px 8px', background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: 5 }}>
|
|
<div style={{ width: 14, height: 14, borderRadius: '50%', background: '#10b981', color: '#fff', fontSize: 10, display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 700 }}>✓</div>
|
|
<div style={{ fontSize: 10, color: '#065f46', fontWeight: 500 }}>尺寸 9:16 · 时长 5s</div>
|
|
</div>
|
|
</div>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 4,
|
|
padding: '6px 0',
|
|
background: 'linear-gradient(135deg, #6366f1, #8b5cf6)',
|
|
color: '#fff',
|
|
borderRadius: 5,
|
|
fontSize: 11,
|
|
fontWeight: 600,
|
|
boxShadow: '0 2px 6px rgba(99,102,241,0.25)',
|
|
}}>
|
|
<ThunderboltOutlined style={{ fontSize: 11 }} />
|
|
确认并生成素材
|
|
</div>
|
|
</div>
|
|
<div style={{
|
|
background: '#f1f5f9',
|
|
borderRadius: 10,
|
|
padding: '14px 12px',
|
|
textAlign: 'center',
|
|
fontSize: 13,
|
|
color: '#475569',
|
|
lineHeight: 1.6,
|
|
}}>
|
|
核对图片 / 视频参数与优化后的提示词,确认后一键生成素材
|
|
</div>
|
|
</div>
|
|
<div
|
|
onClick={() => navigate('/projects')}
|
|
onMouseEnter={(e) => {
|
|
e.currentTarget.style.transform = 'translateY(-2px) scale(1.05)';
|
|
e.currentTarget.style.boxShadow = '0 14px 32px rgba(99,102,241,0.45)';
|
|
const arrow = e.currentTarget.querySelector('.round-arrow') as HTMLElement | null;
|
|
if (arrow) arrow.style.transform = 'translateX(3px)';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
e.currentTarget.style.transform = 'translateY(0) scale(1)';
|
|
e.currentTarget.style.boxShadow = '0 8px 20px rgba(99,102,241,0.30)';
|
|
const arrow = e.currentTarget.querySelector('.round-arrow') as HTMLElement | null;
|
|
if (arrow) arrow.style.transform = 'translateX(0)';
|
|
}}
|
|
style={{
|
|
cursor: 'pointer',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 4,
|
|
width: 64,
|
|
height: 64,
|
|
borderRadius: '50%',
|
|
textAlign: 'center',
|
|
background: 'linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%)',
|
|
color: '#fff',
|
|
fontSize: 14,
|
|
fontWeight: 600,
|
|
letterSpacing: 0.5,
|
|
boxShadow: '0 8px 20px rgba(99,102,241,0.30)',
|
|
transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)',
|
|
userSelect: 'none',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<span style={{
|
|
position: 'absolute',
|
|
inset: 0,
|
|
borderRadius: '50%',
|
|
background: 'radial-gradient(circle at 30% 25%, rgba(255,255,255,0.35) 0%, transparent 55%)',
|
|
pointerEvents: 'none',
|
|
}} />
|
|
前往
|
|
<ArrowRightOutlined
|
|
className="round-arrow"
|
|
style={{ fontSize: 13, transition: 'transform 0.3s ease' }}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
</div> */}
|
|
|
|
{/* ========== AI 创作入口区域 ========== */}
|
|
<div className="animate-fadeInUp" style={{
|
|
padding: '20px',
|
|
borderRadius: 16,
|
|
background: '#fff',
|
|
border: '1px solid #e2e8f0',
|
|
marginBottom: 20,
|
|
}}>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 8,
|
|
marginBottom: 16,
|
|
}}>
|
|
<div style={{
|
|
width: 4, height: 18, borderRadius: 2,
|
|
background: 'linear-gradient(180deg, #6366f1, #a855f7)',
|
|
}} />
|
|
<div style={{ fontSize: 17, fontWeight: 700, color: '#1f2937', letterSpacing: 0.3 }}>
|
|
AI 创作入口
|
|
</div>
|
|
<div style={{ fontSize: 12, color: '#94a3b8', marginLeft: 8 }}>
|
|
一键开启智能创作
|
|
</div>
|
|
</div>
|
|
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 12 }}>
|
|
{aiEntries.map((entry, index) => {
|
|
const accentMap = [
|
|
{ color: '#3b82f6', light: 'rgba(59,130,246,0.12)', tag: '项目' },
|
|
{ color: '#6366f1', light: 'rgba(99,102,241,0.12)', tag: '复刻' },
|
|
{ color: '#f97316', light: 'rgba(249,115,22,0.12)', tag: '拆镜' },
|
|
{ color: '#10b981', light: 'rgba(16,185,129,0.12)', tag: '云创' },
|
|
];
|
|
const accent = accentMap[index] || accentMap[0];
|
|
return (
|
|
<div
|
|
key={index}
|
|
onClick={() => navigate(entry.path)}
|
|
className="project-card"
|
|
style={{
|
|
flex: '1 1 280px',
|
|
minWidth: 280,
|
|
padding: '16px 20px',
|
|
borderRadius: 16,
|
|
background: '#fff',
|
|
border: '1px solid #e2e8f0',
|
|
cursor: 'pointer',
|
|
transition: 'all 0.3s cubic-bezier(0.4,0,0.2,1)',
|
|
position: 'relative',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 14,
|
|
minHeight: 96,
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
e.currentTarget.style.borderColor = accent.color;
|
|
e.currentTarget.style.boxShadow = `0 8px 24px ${accent.light}`;
|
|
e.currentTarget.style.background = accent.light;
|
|
e.currentTarget.style.transform = 'translateY(-2px)';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
e.currentTarget.style.borderColor = '#e2e8f0';
|
|
e.currentTarget.style.boxShadow = 'none';
|
|
e.currentTarget.style.background = '#fff';
|
|
e.currentTarget.style.transform = 'translateY(0)';
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
width: 48, height: 48,
|
|
borderRadius: 12,
|
|
background: accent.light,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
flexShrink: 0,
|
|
transition: 'all 0.3s ease',
|
|
color: accent.color,
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
e.currentTarget.style.background = accent.color;
|
|
e.currentTarget.style.color = '#fff';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
e.currentTarget.style.background = accent.light;
|
|
e.currentTarget.style.color = accent.color;
|
|
}}
|
|
>
|
|
<span style={{ fontSize: 20, display: 'flex', transition: 'all 0.3s ease' }}>{entry.icon}</span>
|
|
</div>
|
|
<div style={{ flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: 4 }}>
|
|
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
|
<span style={{ fontSize: 15, fontWeight: 600, color: '#1e293b', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', flex: 1, minWidth: 0 }}>
|
|
{entry.title}
|
|
</span>
|
|
<span style={{
|
|
fontSize: 10, color: accent.color,
|
|
padding: '2px 7px', borderRadius: 4,
|
|
background: accent.light, fontWeight: 600,
|
|
flexShrink: 0,
|
|
}}>{accent.tag}</span>
|
|
</div>
|
|
<div style={{
|
|
fontSize: 12,
|
|
color: '#64748b',
|
|
lineHeight: 1.5,
|
|
display: '-webkit-box',
|
|
WebkitLineClamp: 2,
|
|
WebkitBoxOrient: 'vertical',
|
|
overflow: 'hidden',
|
|
}}>
|
|
{entry.description}
|
|
</div>
|
|
</div>
|
|
<div style={{
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 4,
|
|
color: accent.color,
|
|
fontSize: 13,
|
|
fontWeight: 600,
|
|
flexShrink: 0,
|
|
}}>
|
|
{entry.action}
|
|
<ArrowRightOutlined style={{ fontSize: 12 }} />
|
|
</div>
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
|
|
{/* ========== 作品与案例区域 ========== */}
|
|
<div className="animate-fadeInUp" style={{
|
|
padding: '24px 28px',
|
|
borderRadius: 16,
|
|
background: '#fff',
|
|
border: '1px solid #e2e8f0',
|
|
}}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
|
|
{/* <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
|
|
<div style={{
|
|
width: 4, height: 18, borderRadius: 2,
|
|
background: 'linear-gradient(180deg, #6366f1, #a855f7)',
|
|
}} />
|
|
<div style={{ fontSize: 17, fontWeight: 700, color: '#1f2937', letterSpacing: 0.3 }}>
|
|
{activeContentTab === 'works' ? '近期作品' : '素材案例'}
|
|
</div>
|
|
</div> */}
|
|
|
|
{/* 外层Tab切换:近期作品 / 素材案例 */}
|
|
<div style={{ display: 'flex', gap: 8 }}>
|
|
{[
|
|
{ key: 'cases', label: '素材案例' },
|
|
|
|
{ key: 'works', label: '近期作品' },
|
|
].map((item) => (
|
|
<button
|
|
key={item.key}
|
|
onClick={() => setActiveContentTab(item.key as 'cases' | 'works')}
|
|
style={{
|
|
padding: '6px 16px',
|
|
borderRadius: 8,
|
|
fontSize: 13,
|
|
fontWeight: 500,
|
|
border: 'none',
|
|
cursor: 'pointer',
|
|
transition: 'all 0.25s ease',
|
|
background: activeContentTab === item.key
|
|
? 'linear-gradient(135deg, #6366f1, #8b5cf6)'
|
|
: '#f1f5f9',
|
|
color: activeContentTab === item.key ? '#fff' : '#64748b',
|
|
}}
|
|
>
|
|
{item.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 内容区域 */}
|
|
{activeContentTab === 'works' ? (
|
|
<>
|
|
{/* 近期作品子Tab */}
|
|
<div style={{ marginBottom: 20 }}>
|
|
<Tabs
|
|
activeKey={activeTab}
|
|
onChange={handleTabChange}
|
|
items={tabs.map(tab => ({
|
|
key: tab.key,
|
|
label: tab.label,
|
|
}))}
|
|
className="homepage-tabs"
|
|
/>
|
|
</div>
|
|
|
|
{/* 近期作品网格 */}
|
|
<div className="stagger-children" style={{ display: 'grid', gridTemplateColumns: 'repeat(5, 1fr)', gap: 16 }}>
|
|
{filteredVideos.length === 0 ? (
|
|
<div style={{
|
|
gridColumn: '1 / -1',
|
|
padding: '60px 0',
|
|
textAlign: 'center',
|
|
color: '#94a3b8',
|
|
fontSize: 14,
|
|
}}>
|
|
<PictureOutlined style={{ fontSize: 36, color: '#cbd5e1', marginBottom: 8 }} />
|
|
<div>暂无作品</div>
|
|
</div>
|
|
) : filteredVideos.map((video) => (
|
|
<div
|
|
key={video.id || `${video.type}-${Math.random()}`}
|
|
className="project-card"
|
|
onClick={() => {
|
|
const id = video.moduleProjectId;
|
|
if (video.type === 'hotOpeningReplicate' && id != null) {
|
|
navigate(`/initial/${id}/initialinfo`);
|
|
} else if (video.type === 'shotReplicate' && id != null) {
|
|
navigate(`/removelens/${id}/removefenbu`);
|
|
} else if (video.type === 'chatAi') {
|
|
navigate(`/conversation`);
|
|
} else if (video.type === 'project') {
|
|
navigate(`/project`);
|
|
}
|
|
}}
|
|
style={{
|
|
borderRadius: 12,
|
|
overflow: 'hidden',
|
|
cursor: 'pointer',
|
|
background: '#fff',
|
|
border: '1px solid #e2e8f0',
|
|
}}
|
|
>
|
|
<div style={{
|
|
position: 'relative',
|
|
aspectRatio: '16/9',
|
|
}}>
|
|
{(() => {
|
|
const apiBase = (import.meta.env.VITE_API_BASE as string) || 'http://localhost:8000';
|
|
const isImage = video.type !== 'hotOpeningReplicate'
|
|
&& (
|
|
String(video.resourceType ?? '').toLowerCase() === 'image'
|
|
|| video.resourceType === 1
|
|
|| String(video.resourceType ?? '') === '1'
|
|
);
|
|
let rawPath = '';
|
|
if (isImage) {
|
|
rawPath = '/static' + video.resultUrl + '&w=300&p=50' || '';
|
|
} else if (video.type === 'hot') {
|
|
rawPath = video.coverUrl || video.resultUrl || video.resultUrl || '';
|
|
} else {
|
|
rawPath = video.coverUrl || video.resultUrl || video.resultUrl || '';
|
|
}
|
|
const src = rawPath
|
|
? (rawPath.startsWith('http') ? rawPath : apiBase + rawPath)
|
|
: '';
|
|
return (
|
|
<img
|
|
src={src}
|
|
alt={video.title || video.name || '作品'}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
);
|
|
})()}
|
|
{(() => {
|
|
const isImage = String(video.resourceType ?? '').toLowerCase() === 'image';
|
|
if (isImage) return null;
|
|
return (
|
|
<div style={{
|
|
position: 'absolute',
|
|
inset: 0,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
background: 'rgba(0,0,0,0.2)',
|
|
}}>
|
|
<VideoCameraOutlined style={{ fontSize: 28, color: '#fff' }} />
|
|
</div>
|
|
);
|
|
})()}
|
|
</div>
|
|
<div style={{
|
|
padding: '10px 12px',
|
|
background: '#f8fafc',
|
|
paddingTop: 0,
|
|
}}>
|
|
<div style={{
|
|
marginTop: 6,
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 6,
|
|
fontSize: 12,
|
|
color: '#64748b',
|
|
}}>
|
|
{(() => {
|
|
const moduleMap: Record<string, string> = {
|
|
project: '项目媒体',
|
|
chatAi: 'AI成片',
|
|
hotOpeningReplicate: '爆款复刻',
|
|
shotReplicate: '拆镜复刻',
|
|
};
|
|
const moduleLabel = moduleMap[video.type] || '其他';
|
|
return (
|
|
<span style={{
|
|
display: 'inline-block',
|
|
padding: '1px 6px',
|
|
border: '1px solid #3b82f6',
|
|
borderRadius: 4,
|
|
color: '#3b82f6',
|
|
fontSize: 11,
|
|
fontWeight: 500,
|
|
background: '#fff',
|
|
lineHeight: 1.4,
|
|
whiteSpace: 'nowrap',
|
|
}}>
|
|
{moduleLabel}
|
|
</span>
|
|
);
|
|
})()}
|
|
<span style={{ color: '#94a3b8' }}>·</span>
|
|
<span style={{ whiteSpace: 'nowrap' }}>{formatShortDate(video.generatedTime)}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</>
|
|
) : (
|
|
<>
|
|
{/* 素材案例子Tab */}
|
|
<div style={{ marginBottom: 20 }}>
|
|
<Tabs
|
|
activeKey={activeCaseTab}
|
|
onChange={(key) => {
|
|
setActiveCaseTab(key);
|
|
getHomeCaseButton(key).then((btnRes: any) => {
|
|
if (btnRes?.categories?.[0]?.assets) {
|
|
setCaseAssets(btnRes.categories[0].assets);
|
|
} else {
|
|
setCaseAssets([]);
|
|
}
|
|
});
|
|
}}
|
|
items={caseHeader.map((item: any) => ({
|
|
key: item.id,
|
|
label: item.name,
|
|
}))}
|
|
className="homepage-tabs"
|
|
/>
|
|
</div>
|
|
|
|
{/* 素材案例网格 */}
|
|
<div className="stagger-children" style={{ display: 'flex', flexWrap: 'wrap', gap: 16, justifyContent: 'space-between', overflowX: 'auto', paddingBottom: 8 }}>
|
|
{caseAssets.length === 0 ? (
|
|
<div style={{
|
|
flex: 1,
|
|
padding: '60px 0',
|
|
textAlign: 'center',
|
|
color: '#94a3b8',
|
|
fontSize: 14,
|
|
}}>
|
|
<PictureOutlined style={{ fontSize: 36, color: '#cbd5e1', marginBottom: 8 }} />
|
|
<div>暂无素材</div>
|
|
</div>
|
|
) : caseAssets.map((asset: any, index: number) => (
|
|
<CaseAssetCard
|
|
key={asset.id || index}
|
|
asset={asset}
|
|
index={index}
|
|
onPreview={setPreviewAsset}
|
|
/>
|
|
))}
|
|
</div>
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
{/* ========== 预览弹窗 ========== */}
|
|
<Modal
|
|
open={!!previewAsset}
|
|
onCancel={() => {
|
|
previewVideoRef.current?.pause();
|
|
setPreviewAsset(null);
|
|
setAspectRatio('');
|
|
currentAssetIdRef.current = '';
|
|
}}
|
|
footer={null}
|
|
width={900}
|
|
centered
|
|
className="preview-modal"
|
|
style={{ borderRadius: 16, overflow: 'hidden' }}
|
|
>
|
|
<div style={{ display: 'flex', height: 580 ,paddingTop: 30}}>
|
|
{/* 左侧:素材预览 */}
|
|
<div style={{ flex: 1, position: 'relative', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 24 }}>
|
|
<div style={{ maxWidth: '100%', maxHeight: 500, borderRadius: 12, overflow: 'hidden', background: '#0f172a' }}>
|
|
{previewAsset?.mediaType === 'video' ? (
|
|
<video
|
|
ref={previewVideoRef}
|
|
src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewAsset.url}`}
|
|
controls
|
|
autoPlay
|
|
style={{ maxWidth: '100%', maxHeight: 500, objectFit: 'contain' }}
|
|
webkit-playsinline="true"
|
|
/>
|
|
) : (
|
|
<img
|
|
src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewAsset?.url}`}
|
|
alt={previewAsset?.title}
|
|
style={{ maxWidth: '100%', maxHeight: 500, objectFit: 'contain' }}
|
|
/>
|
|
)}
|
|
{previewAsset?.mediaType === 'video' && (
|
|
<div style={{
|
|
position: 'absolute',
|
|
top: 32,
|
|
right: 32,
|
|
fontSize: 11,
|
|
color: '#fff',
|
|
background: 'rgba(0,0,0,0.6)',
|
|
padding: '3px 8px',
|
|
borderRadius: 4,
|
|
}}>
|
|
AI生成
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 右侧:创意详情 */}
|
|
<div style={{ flex: 1, padding: 24, overflowY: 'auto' }}>
|
|
<div style={{ fontSize: 16, fontWeight: 600, color: '#fff', marginBottom: 16 }}>
|
|
创意详情
|
|
</div>
|
|
|
|
{/* 热度 */}
|
|
{/* <div style={{ display: 'flex', alignItems: 'center', gap: 16, marginBottom: 16 }}>
|
|
<div style={{ fontSize: 12, color: '#94a3b8' }}>
|
|
<span style={{ color: '#f59e0b' }}>热度:</span>
|
|
{previewAsset?.likes || Math.floor(Math.random() * 5000)}
|
|
</div>
|
|
<div style={{ fontSize: 12, color: '#94a3b8' }}>
|
|
<span style={{ color: '#6366f1' }}>热度:</span>
|
|
{Math.floor(Math.random() * 1000)}
|
|
</div>
|
|
</div> */}
|
|
|
|
<div style={{ fontSize: 12, color: '#94a3b8', marginBottom: 16 }}>
|
|
<span style={{ color: '#6366f1' }}>比例:</span>
|
|
{aspectRatio || '计算中...'}
|
|
</div>
|
|
{/* 视频提示词 */}
|
|
<div style={{ marginBottom: 16 }}>
|
|
<div style={{ fontSize: 12, color: '#000000ff', marginBottom: 8 }}>视频提示词</div>
|
|
<div style={{ fontSize: 13, color: '#000000ff', lineHeight: 1.6 }}>
|
|
{previewAsset?.generationPrompt }
|
|
</div>
|
|
</div>
|
|
|
|
{/* 视频参考图 */}
|
|
<div style={{ marginBottom: 16 }}>
|
|
<div style={{ fontSize: 12, color: '#94a3b8', marginBottom: 8 }}>视频参考图</div>
|
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
|
{previewAsset?.mediaReferences && previewAsset.mediaReferences.length > 0 ? (
|
|
previewAsset.mediaReferences.map((ref: any, index: number) => {
|
|
const url = ref.url || ref.resourceUrl || ref.previewUrl || '';
|
|
const fullUrl = url.startsWith('http') ? url : `${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${url}`;
|
|
|
|
if (ref.type === 'video') {
|
|
return (
|
|
<div key={index} style={{ width: 80, height: 80, borderRadius: 8, overflow: 'hidden', cursor: 'pointer', position: 'relative' }}>
|
|
<video
|
|
src={fullUrl}
|
|
muted
|
|
onClick={(e) => {
|
|
e.stopPropagation();
|
|
const video = e.currentTarget as HTMLVideoElement;
|
|
if (playingVideoIndex === index) {
|
|
video.pause();
|
|
setPlayingVideoIndex(null);
|
|
} else {
|
|
const allVideos = document.querySelectorAll('.preview-video-item');
|
|
allVideos.forEach((v) => {
|
|
(v as HTMLVideoElement).pause();
|
|
});
|
|
video.play();
|
|
setPlayingVideoIndex(index);
|
|
}
|
|
}}
|
|
className="preview-video-item"
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
{playingVideoIndex !== index && (
|
|
<div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'rgba(0,0,0,0.3)' }}>
|
|
<VideoCameraOutlined style={{ fontSize: 18, color: '#fff' }} />
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} else if (ref.type === 'audio') {
|
|
return (
|
|
<div key={index} onClick={(e) => {
|
|
e.stopPropagation();
|
|
if (playingAudioUrl === fullUrl) {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause();
|
|
}
|
|
setPlayingAudioUrl(null);
|
|
} else {
|
|
if (audioRef.current) {
|
|
audioRef.current.pause();
|
|
}
|
|
const audio = new Audio(fullUrl);
|
|
audioRef.current = audio;
|
|
audio.onended = () => {
|
|
setPlayingAudioUrl(null);
|
|
};
|
|
audio.play();
|
|
setPlayingAudioUrl(fullUrl);
|
|
}
|
|
}} style={{ width: 80, height: 80, borderRadius: 8, overflow: 'hidden', cursor: 'pointer', background: 'linear-gradient(135deg, #8b5cf6, #a78bfa)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
|
{playingAudioUrl === fullUrl ? (
|
|
<PauseOutlined style={{ fontSize: 24, color: '#fff' }} />
|
|
) : (
|
|
<AudioOutlined style={{ fontSize: 24, color: '#fff' }} />
|
|
)}
|
|
</div>
|
|
);
|
|
} else {
|
|
return (
|
|
<div key={index} style={{ width: 80, height: 80, borderRadius: 8, overflow: 'hidden', cursor: 'pointer' }}>
|
|
<img
|
|
src={fullUrl}
|
|
alt={`参考图 ${index + 1}`}
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|
|
})
|
|
) : (
|
|
<>
|
|
{/* <div style={{ width: 80, height: 80, borderRadius: 8, overflow: 'hidden', cursor: 'pointer' }}>
|
|
<img
|
|
src={`${import.meta.env.VITE_API_BASE || "http://localhost:8000"}${previewAsset?.url}`}
|
|
alt="参考图"
|
|
style={{ width: '100%', height: '100%', objectFit: 'cover' }}
|
|
/>
|
|
</div>
|
|
<div style={{
|
|
width: 80,
|
|
height: 80,
|
|
borderRadius: 8,
|
|
border: '1px dashed #475569',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
color: '#64748b',
|
|
fontSize: 12,
|
|
}}>
|
|
展开查看
|
|
</div> */}
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 口播脚本台词 */}
|
|
{/* <div style={{ marginBottom: 16 }}>
|
|
<div style={{ fontSize: 12, color: '#000000ff', marginBottom: 8 }}>口播脚本台词</div>
|
|
<div style={{ fontSize: 13, color: '#000000ff', lineHeight: 1.6 }}>
|
|
{previewAsset?.script || '还在为宝宝不爱喝水发愁?试试这款天然果蔬汁!零添加糖分,维生素满满,口感清甜宝宝超爱喝。现在下单还送专属吸管杯,手慢无!点下方链接把健康带回家~'}
|
|
</div>
|
|
<div style={{
|
|
fontSize: 12,
|
|
color: '#6366f1',
|
|
marginTop: 8,
|
|
cursor: 'pointer',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
gap: 4,
|
|
}}>
|
|
完整内容女声
|
|
</div>
|
|
</div> */}
|
|
|
|
{/* 视频标签 */}
|
|
{/* <div style={{ marginBottom: 16 }}>
|
|
<div style={{ fontSize: 12, color: '#94a3b8', marginBottom: 8 }}>视频标签</div>
|
|
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
|
|
{previewAsset?.tags?.split?.(',')?.map((tag: string, i: number) => (
|
|
<span
|
|
key={i}
|
|
style={{
|
|
padding: '4px 10px',
|
|
borderRadius: 16,
|
|
background: '#334155',
|
|
color: '#94a3b8',
|
|
fontSize: 11,
|
|
}}
|
|
>
|
|
{tag.trim()}
|
|
</span>
|
|
)) || ['互联网电商服务', '美妆', '美妆', '服装配饰', '母婴宠物', '带货主播', '口播'].map((tag, i) => (
|
|
<span
|
|
key={i}
|
|
style={{
|
|
padding: '4px 10px',
|
|
borderRadius: 16,
|
|
background: '#334155',
|
|
color: '#94a3b8',
|
|
fontSize: 11,
|
|
}}
|
|
>
|
|
{tag}
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div> */}
|
|
</div>
|
|
</div>
|
|
|
|
{/* 底部操作栏 */}
|
|
<div style={{
|
|
padding: '16px 24px',
|
|
borderTop: '1px solid #334155',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'flex-end',
|
|
}}>
|
|
{/* <div style={{ display: 'flex', gap: 16 }}>
|
|
<button
|
|
onClick={() => message.info('收藏功能开发中')}
|
|
style={{
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: '50%',
|
|
border: 'none',
|
|
background: '#334155',
|
|
color: '#94a3b8',
|
|
cursor: 'pointer',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
transition: 'all 0.2s',
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
(e.currentTarget as HTMLElement).style.background = '#475569';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
(e.currentTarget as HTMLElement).style.background = '#334155';
|
|
}}
|
|
>
|
|
<StarOutlined style={{ fontSize: 16 }} />
|
|
</button>
|
|
<button
|
|
onClick={() => message.info('分享功能开发中')}
|
|
style={{
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: '50%',
|
|
border: 'none',
|
|
background: '#334155',
|
|
color: '#000000ff',
|
|
cursor: 'pointer',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
transition: 'all 0.2s',
|
|
}}
|
|
onMouseEnter={(e) => {
|
|
(e.currentTarget as HTMLElement).style.background = '#475569';
|
|
}}
|
|
onMouseLeave={(e) => {
|
|
(e.currentTarget as HTMLElement).style.background = '#334155';
|
|
}}
|
|
>
|
|
<ShareAltOutlined style={{ fontSize: 16 }} />
|
|
</button>
|
|
</div> */}
|
|
|
|
<div style={{ display: 'flex', gap: 12 }}>
|
|
{/* {previewAsset?.mediaType !== 'video' && ( */}
|
|
<Button
|
|
onClick={() => {
|
|
navigate('/conversation', {
|
|
state: {
|
|
generationPrompt: previewAsset?.generationPrompt,
|
|
mediaReferences: previewAsset?.mediaReferences,
|
|
aspectRatio: aspectRatio,
|
|
},
|
|
});
|
|
}}
|
|
style={{
|
|
padding: '8px 24px',
|
|
borderRadius: 8,
|
|
background: '#3b82f6',
|
|
border: 'none',
|
|
color: '#fff',
|
|
fontSize: 13,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
去AI创作
|
|
</Button>
|
|
{/* )}
|
|
<Button
|
|
// onClick={() => navigate('/initial')}
|
|
style={{
|
|
padding: '8px 24px',
|
|
borderRadius: 8,
|
|
background: '#8b5cf6',
|
|
border: 'none',
|
|
color: '#fff',
|
|
fontSize: 13,
|
|
fontWeight: 500,
|
|
}}
|
|
>
|
|
去爆款复刻
|
|
</Button> */}
|
|
</div>
|
|
</div>
|
|
</Modal>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default HomePage;
|