From 41b597a7854980418787be7d9a98423473a7383b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E4=BD=B3=E8=89=BA?= Date: Mon, 8 Jun 2026 09:13:29 +0800 Subject: [PATCH] =?UTF-8?q?=E7=99=BB=E5=BD=95=E9=AA=8C=E8=AF=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- video-gen-app/src/api/index.ts | 17 +- video-gen-app/src/pages/GenerateConver.tsx | 518 +++++++++++++-------- video-gen-app/src/pages/LoginPage.tsx | 335 ++++++++++++- 3 files changed, 640 insertions(+), 230 deletions(-) diff --git a/video-gen-app/src/api/index.ts b/video-gen-app/src/api/index.ts index ccd66567..762389f1 100644 --- a/video-gen-app/src/api/index.ts +++ b/video-gen-app/src/api/index.ts @@ -20,6 +20,12 @@ export async function login(username: string, password: string, captchaToken?: s setToken(res.accessToken); return res.user; } +export async function phonelogin(phone: string, code: string): Promise { + // if (USE_MOCK) return mock.mockLogin({ username, password }); + const res = await api.post<{ accessToken: string; user: User }>('/auth/sms-login', { phone, code }, false); + setToken(res.accessToken); + return res.user; +} export async function register(phone: string, code: string, password: string): Promise { const res = await api.post<{ accessToken: string; user: User }>('/auth/register', { phone, code, password }, false); @@ -211,9 +217,9 @@ export async function getParameters(): Promise { // ── SMS ─────────────────────────────────────────────────── -export async function sendSms(phone: string, captchaToken?: string): Promise { +export async function sendSms(phone: string, scene: string): Promise { if (USE_MOCK) return; - await api.post('/sms/send', { phone, captcha_token: captchaToken }, false); + await api.post('/sms/send', { phone, scene: scene }, false); } export async function verifySms(phone: string, code: string): Promise<{ token: string }> { @@ -351,3 +357,10 @@ export async function deleteHistory(id: string): Promise { export async function calculateCredits(): Promise { return api.get('/credits/credit-ratios'); } + + + +// 获取验证码 +export async function getSendcode(phone: string): Promise { + return api.post('/sms/send', { phone }); +} diff --git a/video-gen-app/src/pages/GenerateConver.tsx b/video-gen-app/src/pages/GenerateConver.tsx index f212c77a..65d82276 100644 --- a/video-gen-app/src/pages/GenerateConver.tsx +++ b/video-gen-app/src/pages/GenerateConver.tsx @@ -17,7 +17,7 @@ import { import { getParameters, createGenerationTask, getgen_list, getEngine, uploadImage, - uploadVideo, getCreditRatios, deleteHistory,calculateCredits + uploadVideo, getCreditRatios, deleteHistory, calculateCredits } from '../api'; import { @@ -119,6 +119,7 @@ const AIChatPage: React.FC = () => { const [previewVisible, setPreviewVisible] = useState(false); const [previewUrl, setPreviewUrl] = useState(''); const [previewType, setPreviewType] = useState<'image' | 'video'>('image'); + const videoRef = useRef(null); // 从URL中提取exp时间戳(支持相对路径和完整URL) const extractExpTimestamp = (url: string): number | null => { @@ -209,20 +210,48 @@ const AIChatPage: React.FC = () => { // 获取预估积分 - 根据引擎ID、类型和分辨率计算 const getEstimatedCredits = (): number => { // 根据当前选择的引擎ID、类型和分辨率查找对应的积分配置 - const config = creditCalculationData.find((item: any) => - item.modelConfigId === countType && + let config: any = {}; + config = creditCalculationData.find((item: any) => + item.modelConfigId === countType && item.genType === mediaType && item.resolution === (mediaType === 'video' ? videoResolution : selectedResolution) ); - + if (!config) { - return 0; + if (mediaType === 'video') { + // 如果没有找到对应的配置,则使用默认配置 + config = { + perSecondCredits: 2, + baseCredits: 60, + ratio: 1, + }; + if (videoResolution === '1080p') { + config.ratio = 2; + } else if (videoResolution === '720p') { + config.ratio = 1.5; + } else if (videoResolution === '480p') { + config.ratio = 1; + } + } + else { + // 如果没有找到对应的配置,则使用默认配置 + config = { + perSecondCredits: 0.1, + baseCredits: 4, + ratio: 1, + }; + if (selectedResolution === '2K') { + config.ratio = 1; + } else if (selectedResolution === '4K') { + config.ratio = 2; + } + } } console.log(config); - - + + // 根据配置计算积分 if (mediaType === 'video') { // 视频:(秒数 × perSecondCredits + baseCredits) × ratio @@ -315,7 +344,7 @@ const AIChatPage: React.FC = () => { useEffect(() => { getEngine() .then((data: any) => { - console.log('引擎', data); + // console.log('引擎', data); setEnginesele(data.engine); @@ -345,18 +374,18 @@ const AIChatPage: React.FC = () => { }); getCreditRatios() .then((data: any) => { - console.log('积分', data); + // console.log('积分', data); setCreditRatios(data.video || []); setCimage(data.image || []); }) .catch((error) => { }); - calculateCredits().then((data: any) => { - console.log('积分计算', data); - // 保存积分计算数据 - setCreditCalculationData(data); - }) + calculateCredits().then((data: any) => { + // console.log('积分计算', data); + // 保存积分计算数据 + setCreditCalculationData(data); + }) getgen_list(Pagebreak).then((data: any) => { let mess_list = data.items let total = data.total @@ -775,6 +804,9 @@ const AIChatPage: React.FC = () => { const handleClosePreview = () => { setPreviewVisible(false); setPreviewUrl(''); + if (videoRef.current) { + videoRef.current.pause(); + } }; const handleDownload = (e: React.MouseEvent) => { @@ -975,218 +1007,289 @@ const AIChatPage: React.FC = () => { {(() => { const msgApi = message; return gen_list.map((msg) => ( -
-
- {/* 头像 */} -
- -
- - {/* 消息内容 */} -
- - {/* 消息气泡 */} +
+
+ {/* 头像 */}
- {/* 删除按钮 - 右上角 */} -
- { - await deleteHistory(msg.id); - msgApi.success('删除成功'); - // 直接在本地列表中删除对应数据 - setGen_list(prev => prev.filter(item => item.id !== msg.id)); - setTotalnumber(prev => prev - 1); - }} - okText="确定" - cancelText="取消" + +
+ + {/* 消息内容 */} +
+ {/* 时间戳和参数信息 */} + +
+ {msg.createdAt?.replace('T', ' ').split('.')[0]} + {/* 引擎标签 */} + + {/* */} + {msg.engineSnapshot.name} + + {/* 参数标签 */} + + {/* */} + {msg.genType === 'image' + ? `${msg.imageProportion || ''} · ${msg.imagePx || ''} · ${msg.imageSize || ''}` + : `${msg.duration || ''}s · ${msg.aspectRatio || ''} · ${msg.resolution || ''}` + } + + 消耗积分:{msg.creditsCost} + {msg.mediaReferences && msg.mediaReferences.length > 0 && ( + { + e.stopPropagation(); + const target = e.currentTarget as HTMLElement; + const rect = target.getBoundingClientRect(); + setAttachmentPopupPosition({ + x: rect.left, + y: rect.top - 10 + }); + setAttachmentPopupMessageId(msg.id); + setAttachmentPopupVisible(true); + }} + > + 附件详情 + + + )} +
+ {/* 消息气泡 */} +
+ {/* 删除按钮 - 右上角 */} +
+ { + try { + await deleteHistory(msg.id); + msgApi.success('删除成功'); + // 直接在本地列表中删除对应数据 + setGen_list(prev => prev.filter(item => item.id !== msg.id)); + setTotalnumber(prev => prev - 1); + } catch (error: any) { + console.log(error); + + const errorMsg = error?.response?.data?.message || error?.message || '删除失败'; + msgApi.error(errorMsg); + } + }} + okText="确定" + cancelText="取消" + > + + +
+ + {/* 文本内容 */} + - - -
- - {/* 文本内容 */} -

- {msg.originalPrompt} - -

- - - {/* 根据 status 显示不同内容 */} - {/* 生成中 - 显示加载动画 */} - {msg.status === 'generating' && ( -
-
-
- 正在生成中 -
- - - + gap: 16 + }}> +
+ 正在生成中... +
+
+
+ )} + {/* 生成失败 - 显示失败提示 */} + {msg.status === 'failed' && ( +
+
+
+
+ 生成失败 + {/* 请重试 */}
-
- )} - {/* 生成失败 - 显示失败提示 */} - {msg.status === 'failed' && ( -
- - 生成失败,请重试 -
- )} - {/* 已完成 - 显示媒体内容 */} - {msg.status === 'completed' && ( -
-
{ - setPreviewUrl(msg.genType === 'image' ? msg.imageUrl : msg.videoUrl); - setPreviewType(msg.genType === 'image' ? 'image' : 'video'); - setPreviewVisible(true); - }} - style={{ cursor: 'pointer', overflow: 'hidden', borderRadius: 8, position: 'relative', height: 200 }} - > - {msg.genType === 'image' ? ( - {msg.name} { e.currentTarget.style.transform = 'scale(1.05)'; }} - onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }} - /> - ) : ( - <> + )} + {/* 已完成 - 显示媒体内容 */} + {msg.status === 'completed' && ( +
+
{ + setPreviewUrl(msg.genType === 'image' ? msg.imageUrl : msg.videoUrl); + setPreviewType(msg.genType === 'image' ? 'image' : 'video'); + setPreviewVisible(true); + }} + style={{ cursor: 'pointer', overflow: 'hidden', borderRadius: 8, position: 'relative', height: 200 }} + > + {msg.genType === 'image' ? ( {msg.name} { e.currentTarget.style.transform = 'scale(1.05)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }} /> - {/* 视频播放按钮 */} -
- - - -
- - )} + ) : ( + <> + {msg.name} { e.currentTarget.style.transform = 'scale(1.05)'; }} + onMouseLeave={(e) => { e.currentTarget.style.transform = 'scale(1)'; }} + /> + {/* 视频播放按钮 */} +
+ + + +
+ + )} +
-
- )} + )} + +
-
- {/* 时间戳和参数信息 */} -
- {msg.createdAt?.replace('T', ' ').split('.')[0]} - {/* 引擎标签 */} - - {/* */} - {msg.engineSnapshot.name} - - {/* 参数标签 */} - - {/* */} - {msg.genType === 'image' - ? `${msg.imageProportion || ''} · ${msg.imagePx || ''} · ${msg.imageSize || ''}` - : `${msg.duration || ''}s · ${msg.aspectRatio || ''} · ${msg.resolution || ''}` - } - - 消耗积分:{msg.creditsCost} - {msg.mediaReferences && msg.mediaReferences.length > 0 && ( - { - e.stopPropagation(); - const target = e.currentTarget as HTMLElement; - const rect = target.getBoundingClientRect(); - setAttachmentPopupPosition({ - x: rect.left, - y: rect.top - 10 - }); - setAttachmentPopupMessageId(msg.id); - setAttachmentPopupVisible(true); - }} - > - 附件详情 - - - )}
-
-
- ))})()} + )) + })()} {/* 消息列表底部标记 - 用于自动滚动 */} @@ -1464,10 +1567,10 @@ const AIChatPage: React.FC = () => { } placeholder="请输入手机号" style={inputStyle} /> @@ -267,7 +349,7 @@ const LoginPage: React.FC = () => { 记住我的登录状态 - + {/* 滑动验证 - 获取验证码后显示 */} + {showSliderVerify && ( + + + + )} + - - } placeholder="请设置密码(至少6位)" style={inputStyle} /> + + {/* 滑动验证 - 获取验证码后显示 */} + {showSliderVerify && ( + + + + )} + -