From dc13ab03e3a2aed5702eabd73dc59fbaa99d7671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Fri, 5 Sep 2025 21:07:22 +0800 Subject: [PATCH 01/20] =?UTF-8?q?=E5=88=A0=E6=8E=89=E4=B9=8B=E5=89=8D?= =?UTF-8?q?=E7=9A=84=E9=89=B4=E6=9D=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 8 ++++---- components/auth/auth-guard.tsx | 2 +- lib/auth.ts | 34 ---------------------------------- 3 files changed, 5 insertions(+), 39 deletions(-) diff --git a/.env.development b/.env.development index 8d5e823..507289b 100644 --- a/.env.development +++ b/.env.development @@ -1,8 +1,8 @@ -# NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com -# NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai -NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai +NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com +NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +# NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai +# NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 \ No newline at end of file diff --git a/components/auth/auth-guard.tsx b/components/auth/auth-guard.tsx index 031197c..2699e6d 100644 --- a/components/auth/auth-guard.tsx +++ b/components/auth/auth-guard.tsx @@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'; import { useRouter, usePathname } from 'next/navigation'; -import { checkAuth, clearAuthData, getUserProfile, isAuthenticated } from '@/lib/auth'; +import { clearAuthData, getUserProfile, isAuthenticated } from '@/lib/auth'; import GlobalLoad from '../common/GlobalLoad'; import { message } from 'antd'; import { errorHandle } from '@/api/errorHandle'; diff --git a/lib/auth.ts b/lib/auth.ts index f6eb482..fb3de7c 100644 --- a/lib/auth.ts +++ b/lib/auth.ts @@ -41,40 +41,6 @@ export const loginUser = async (email: string, password: string) => { } }; -/** - * 鉴权检查 - */ -export const checkAuth = async (): Promise => { - const token = getToken(); - if (!token) { - return false; - } - - try { - const response = await fetch(`${process.env.NEXT_PUBLIC_API_BASE_URL}/admin/login/auth`, { - method: 'POST', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json', - 'X-EASE-ADMIN-TOKEN': token, - }, - }); - - const data = await response.json(); - return true; - // if (data.code === '401' || data.status === 401) { - // // Token无效,清除本地存储 - // // clearAuthData(); - // // return false; - // } - - // return data.code === '200' && data.status === 200; - } catch (error) { - console.error('Auth check failed:', error); - return false; - } -}; - /** * 获取token */ From 24ab37550d370b7b1e1fdb274b18574210f652f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Fri, 5 Sep 2025 21:45:37 +0800 Subject: [PATCH 02/20] =?UTF-8?q?https=20=E5=8D=8F=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 4 ++-- .env.production | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.env.development b/.env.development index 507289b..c4b938b 100644 --- a/.env.development +++ b/.env.development @@ -2,7 +2,7 @@ NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -# NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai -# NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai +# NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai +# NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 \ No newline at end of file diff --git a/.env.production b/.env.production index 8816191..0e97597 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,7 @@ # NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com # NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai -NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai +NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai +NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 From ff49972e89436db0b173ee76abef3385dee2cfc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Fri, 5 Sep 2025 22:07:09 +0800 Subject: [PATCH 03/20] =?UTF-8?q?=E7=8E=AF=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.production | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.env.production b/.env.production index 0e97597..8442c8b 100644 --- a/.env.production +++ b/.env.production @@ -1,7 +1,8 @@ -# NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com -# NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai -NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai + +NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com +NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +# NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai +# NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 From 1f65bb09ed95115ccec481d4114d2dc7cecb58f3 Mon Sep 17 00:00:00 2001 From: dengqinghua Date: Sat, 6 Sep 2025 00:17:59 +0800 Subject: [PATCH 04/20] add --- .env.development | 8 ++++---- .env.production | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.env.development b/.env.development index c4b938b..07a7c41 100644 --- a/.env.development +++ b/.env.development @@ -1,8 +1,8 @@ -NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com -NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -# NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai -# NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai +#NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com +#NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai +NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 \ No newline at end of file diff --git a/.env.production b/.env.production index 8442c8b..c8c77e6 100644 --- a/.env.production +++ b/.env.production @@ -1,8 +1,8 @@ -NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com -NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -# NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai -# NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai +#NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com +#NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai +NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 From 3b437a4828d514e3d4bd4c747312a5db33e41bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 12:03:37 +0800 Subject: [PATCH 05/20] https --- .env.production | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.production b/.env.production index c8c77e6..45cd625 100644 --- a/.env.production +++ b/.env.production @@ -2,7 +2,7 @@ #NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com #NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com -NEXT_PUBLIC_JAVA_URL = http://test.java.movieflow.ai -NEXT_PUBLIC_BASE_URL = http://test.video.movieflow.ai +NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai +NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 From 8590196ff81b5e390105cbd078414ff1ce846aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 14:45:50 +0800 Subject: [PATCH 06/20] =?UTF-8?q?=E5=85=BC=E5=AE=B9=20detail=20=E5=A4=96?= =?UTF-8?q?=E9=9D=A2=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/DTO/movieEdit.ts | 4 ++++ .../pages/work-flow/use-workflow-data.tsx | 21 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/api/DTO/movieEdit.ts b/api/DTO/movieEdit.ts index 28745c0..45690ec 100644 --- a/api/DTO/movieEdit.ts +++ b/api/DTO/movieEdit.ts @@ -363,6 +363,10 @@ export interface VideoFlowProjectResponse { last_message: string; /** 项目内容 */ data: ProjectContentData; + /** 最终简单视频 */ + final_simple_video: string; + /** 最终视频 */ + final_video: string; } /** * 新角色列表项接口 diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index ab3f6d2..a83c883 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -252,7 +252,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = loadingText.current = LOADING_TEXT_MAP.postProduction('AI-powered video editing in progress…'); } } - if (taskObject.currentStage === 'final_video') { + if (taskObject.currentStage === 'final_video' && taskObject.status !== 'COMPLETED') { loadingText.current = LOADING_TEXT_MAP.postProduction('generating fine-grained video clips...'); } if (taskObject.status === 'COMPLETED') { @@ -498,7 +498,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = throw new Error(response.message); } - const { status, data, tags, mode, original_text, title, name } = response.data; + const { status, data, tags, mode, original_text, title, name, final_simple_video, final_video } = response.data; const { current: taskCurrent } = tempTaskObject; @@ -611,6 +611,21 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = } } + // 粗剪 + if (final_simple_video) { + taskCurrent.currentStage = 'final_video'; + taskCurrent.final.url = final_simple_video; + taskCurrent.final.note = 'simple'; + taskCurrent.status = 'COMPLETED'; + } + + if (final_video) { + taskCurrent.currentStage = 'final_video'; + taskCurrent.final.url = final_video; + taskCurrent.final.note = 'final'; + taskCurrent.status = 'COMPLETED'; + } + console.log('---look-taskData', taskCurrent); if (taskCurrent.currentStage === 'script') { @@ -632,7 +647,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = }); // 设置是否需要获取流式数据 - setNeedStreamData(status !== 'COMPLETED'); + setNeedStreamData(taskCurrent.status !== 'COMPLETED'); } catch (error) { console.error('初始化失败:', error); From 0d315227092de2feb30887c843060db8083a6646 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 16:58:21 +0800 Subject: [PATCH 07/20] =?UTF-8?q?=E5=85=A8=E5=B1=80=E6=B6=88=E6=81=AF?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/errorHandle.ts | 7 +- api/request.ts | 1 - app/page.tsx | 2 - .../Interaction/MovieProjectService.ts | 13 +- .../Interaction/templateStoryService.ts | 1 - app/types/global.d.ts | 16 ++ components/common/GlobalMessage.tsx | 92 +++++++++ components/layout/top-bar.tsx | 4 +- components/pages/create-to-video2.tsx | 11 +- .../pages/work-flow/use-workflow-data.tsx | 3 +- components/providers.tsx | 34 +++- components/script-renderer/ScriptRenderer.tsx | 7 +- components/ui/character-tab-content.tsx | 9 +- components/ui/edit-modal.tsx | 7 +- components/ui/oauth-callback-handler.tsx | 90 --------- components/ui/shot-editor/ShotsEditor.tsx | 7 +- components/ui/shot-tab-content.tsx | 5 +- components/ui/sonner.tsx | 31 --- components/ui/toast.tsx | 129 ------------ components/ui/toaster.tsx | 35 ---- hooks/use-toast.ts | 191 ------------------ tsconfig.json | 8 +- 22 files changed, 172 insertions(+), 531 deletions(-) create mode 100644 app/types/global.d.ts create mode 100644 components/common/GlobalMessage.tsx delete mode 100644 components/ui/oauth-callback-handler.tsx delete mode 100644 components/ui/sonner.tsx delete mode 100644 components/ui/toast.tsx delete mode 100644 components/ui/toaster.tsx delete mode 100644 hooks/use-toast.ts diff --git a/api/errorHandle.ts b/api/errorHandle.ts index 50b7fa7..2486b2d 100644 --- a/api/errorHandle.ts +++ b/api/errorHandle.ts @@ -1,4 +1,3 @@ -import { message } from "antd"; import { debounce } from "lodash"; /** @@ -52,11 +51,7 @@ export const errorHandle = debounce( customMessage || HTTP_ERROR_MESSAGES[code] || DEFAULT_ERROR_MESSAGE; // 显示错误提示 - message.error({ - content: errorMessage, - duration: 3, - className: 'custom-error-message' - }); + window.msg.error(errorMessage); // 执行特殊错误码的处理函数 const handler = ERROR_HANDLERS[code]; diff --git a/api/request.ts b/api/request.ts index 7a59dbf..c30cc5a 100644 --- a/api/request.ts +++ b/api/request.ts @@ -1,5 +1,4 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse, InternalAxiosRequestConfig, AxiosHeaders } from 'axios'; -import { message } from "antd"; import { BASE_URL } from './constants' import { errorHandle } from './errorHandle'; diff --git a/app/page.tsx b/app/page.tsx index e2c41ee..782e582 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,13 +1,11 @@ import { TopBar } from "@/components/layout/top-bar"; import { HomePage2 } from "@/components/pages/home-page2"; -import OAuthCallbackHandler from "@/components/ui/oauth-callback-handler"; export default function Home() { return ( <> - ); diff --git a/app/service/Interaction/MovieProjectService.ts b/app/service/Interaction/MovieProjectService.ts index 1d4ebb0..428bd44 100644 --- a/app/service/Interaction/MovieProjectService.ts +++ b/app/service/Interaction/MovieProjectService.ts @@ -1,7 +1,6 @@ -import { CreateMovieProjectV2Request, CreateMovieProjectV3Request } from "@/api/DTO/movie_start_dto"; + import { createMovieProject, createMovieProjectV2, createMovieProjectV3 } from "@/api/create_movie"; -import { QueueResponse, QueueStatus, withQueuePolling, QueueResponseData } from "@/api/movie_queue"; -import { message } from "antd"; +import { QueueResponse, withQueuePolling, QueueResponseData } from "@/api/movie_queue"; /** * 电影项目创建模式 @@ -56,13 +55,13 @@ export class MovieProjectService { }, onError: (error: Error) => { if (error.message === '操作已取消') { - message.info('Queue cancelled'); + window.msg.info('Queue cancelled'); } else { - message.error(error instanceof Error ? error.message : "Failed to create project"); + window.msg.error(error instanceof Error ? error.message : "Failed to create project"); } }, onCancel: () => { - message.info('Queue cancelled'); + window.msg.info('Queue cancelled'); } }); @@ -80,7 +79,7 @@ export class MovieProjectService { if (error instanceof Error && error.message === '操作已取消') { throw error; } - message.error(error instanceof Error ? error.message : "Failed to create project"); + window.msg.error(error instanceof Error ? error.message : "Failed to create project"); throw error; } } diff --git a/app/service/Interaction/templateStoryService.ts b/app/service/Interaction/templateStoryService.ts index 99f8a13..89dacc4 100644 --- a/app/service/Interaction/templateStoryService.ts +++ b/app/service/Interaction/templateStoryService.ts @@ -1,4 +1,3 @@ -import { message } from "antd"; import { StoryTemplateEntity } from "../domain/Entities"; import { useUploadFile } from "../domain/service"; import { debounce } from "lodash"; diff --git a/app/types/global.d.ts b/app/types/global.d.ts new file mode 100644 index 0000000..6136c85 --- /dev/null +++ b/app/types/global.d.ts @@ -0,0 +1,16 @@ +import { GlobalMessage } from '@/components/common/GlobalMessage'; +import { toast } from 'sonner'; + +declare global { + interface Window { + msg: GlobalMessage; + $message: { + success: (message: string, duration?: number) => void; + error: (message: string, duration?: number) => void; + warning: (message: string, duration?: number) => void; + info: (message: string, duration?: number) => void; + loading: (message: string) => ReturnType; + dismiss: () => void; + }; + } +} \ No newline at end of file diff --git a/components/common/GlobalMessage.tsx b/components/common/GlobalMessage.tsx new file mode 100644 index 0000000..a31c859 --- /dev/null +++ b/components/common/GlobalMessage.tsx @@ -0,0 +1,92 @@ +'use client'; + +import { toast, type ToastT } from 'sonner'; +import { + CheckCircle2, + XCircle, + AlertCircle, + Info, + Loader2 +} from 'lucide-react'; + +/** + * 全局消息提示工具 + * 对 sonner toast 进行封装,提供更简洁的 API + */ +class GlobalMessage { + success(message: string, duration = 3000, options?: Partial) { + toast.success(message, { + icon: , + duration, + ...options, + }); + } + + error(message: string, duration = 3000, options?: Partial) { + toast.error(message, { + icon: , + duration, + ...options, + }); + } + + warning(message: string, duration = 3000, options?: Partial) { + toast.warning(message, { + icon: , + duration, + ...options, + }); + } + + info(message: string, duration = 3000, options?: Partial) { + toast(message, { + icon: , + duration, + ...options, + }); + } + + loading(message: string, options?: Partial) { + return toast.promise( + new Promise(() => {}), + { + loading: message, + icon: , + ...options, + } + ); + } + + dismiss() { + toast.dismiss(); + } +} + +// 导出单例实例 +export const msg = new GlobalMessage(); + +// 为了方便使用,也导出单独的方法 +export const { success, error, warning, info, loading, dismiss } = msg; +// 在文件末尾添加全局注册方法 +export function registerGlobalMessage() { + if (typeof window !== 'undefined') { + // 注册完整实例 + window.msg = msg; + + // 注册便捷方法 + window.$message = { + success: msg.success.bind(msg), + error: msg.error.bind(msg), + warning: msg.warning.bind(msg), + info: msg.info.bind(msg), + loading: msg.loading.bind(msg), + dismiss: msg.dismiss.bind(msg), + }; + + // 添加调试信息 + console.log('GlobalMessage registered:', { + msg: window.msg, + $message: window.$message + }); + } +} diff --git a/components/layout/top-bar.tsx b/components/layout/top-bar.tsx index 1f78b40..0be548b 100644 --- a/components/layout/top-bar.tsx +++ b/components/layout/top-bar.tsx @@ -239,9 +239,9 @@ export function TopBar({ collapsed }: { collapsed: boolean }) { )} {/* Notifications */} - {/* */} + {/* Theme Toggle */} {/* + */} {/* Theme Toggle */} {/* diff --git a/hooks/useDeviceType.ts b/hooks/useDeviceType.ts new file mode 100644 index 0000000..a46721f --- /dev/null +++ b/hooks/useDeviceType.ts @@ -0,0 +1,64 @@ +import { useState, useEffect } from 'react'; + +// 定义设备类型枚举 +export enum DeviceType { + MOBILE = 'mobile', // 手机 + TABLET = 'tablet', // 平板 + DESKTOP = 'desktop' // 桌面端 +} + +// 定义屏幕断点 +const BREAKPOINTS = { + MOBILE: 480, // 0-480px 为手机 + TABLET: 1024, // 481-1024px 为平板 + DESKTOP: 1025 // 1025px 及以上为桌面端 +}; + +export function useDeviceType() { + const [deviceType, setDeviceType] = useState(DeviceType.DESKTOP); + const [windowSize, setWindowSize] = useState({ + width: typeof window !== 'undefined' ? window.innerWidth : 0, + height: typeof window !== 'undefined' ? window.innerHeight : 0 + }); + + useEffect(() => { + /** + * 根据窗口宽度判断设备类型 + */ + const getDeviceType = (width: number): DeviceType => { + if (width <= BREAKPOINTS.MOBILE) return DeviceType.MOBILE; + if (width <= BREAKPOINTS.TABLET) return DeviceType.TABLET; + return DeviceType.DESKTOP; + }; + + /** + * 处理窗口大小变化 + */ + const handleResize = () => { + const width = window.innerWidth; + const height = window.innerHeight; + + setWindowSize({ width, height }); + setDeviceType(getDeviceType(width)); + }; + + // 初始化设备类型 + handleResize(); + + // 添加窗口大小变化监听 + window.addEventListener('resize', handleResize); + + // 清理监听器 + return () => { + window.removeEventListener('resize', handleResize); + }; + }, []); + + return { + deviceType, + windowSize, + isMobile: deviceType === DeviceType.MOBILE, + isTablet: deviceType === DeviceType.TABLET, + isDesktop: deviceType === DeviceType.DESKTOP + }; +} \ No newline at end of file From 9c382675a74a29474b9b55096caeb5cdbfc9b0c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 23:25:14 +0800 Subject: [PATCH 11/20] =?UTF-8?q?=E9=85=8D=E7=BD=AE=20cut=20=E7=8E=AF?= =?UTF-8?q?=E5=A2=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 1 + .env.production | 1 + components/pages/work-flow/ai-editing-iframe.tsx | 6 ++++-- components/pages/work-flow/use-workflow-data.tsx | 5 ++++- 4 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.env.development b/.env.development index c4b938b..7409920 100644 --- a/.env.development +++ b/.env.development @@ -2,6 +2,7 @@ NEXT_PUBLIC_JAVA_URL = https://77.app.java.auth.qikongjian.com NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com +NEXT_PUBLIC_CUT_URL = https://smartcut.movieflow.ai # NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai # NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 diff --git a/.env.production b/.env.production index b960205..3bb1344 100644 --- a/.env.production +++ b/.env.production @@ -4,5 +4,6 @@ #NEXT_PUBLIC_BASE_URL = https://77.smartvideo.py.qikongjian.com NEXT_PUBLIC_JAVA_URL = https://auth.movieflow.ai NEXT_PUBLIC_BASE_URL = https://api.video.movieflow.ai +NEXT_PUBLIC_CUT_URL = https://smartcut.movieflow.ai # 失败率 NEXT_PUBLIC_ERROR_CONFIG = 0.2 diff --git a/components/pages/work-flow/ai-editing-iframe.tsx b/components/pages/work-flow/ai-editing-iframe.tsx index 597575a..8b18bfb 100644 --- a/components/pages/work-flow/ai-editing-iframe.tsx +++ b/components/pages/work-flow/ai-editing-iframe.tsx @@ -92,9 +92,11 @@ export const AIEditingIframe = React.forwardRef(null); const progressIntervalRef = useRef(null); const timeoutRef = useRef(null); + const cutUrl = process.env.NEXT_PUBLIC_CUT_URL || 'https://cut.movieflow.ai'; + console.log('cutUrl', cutUrl); // 构建智能剪辑URL - const aiEditingUrl = `https://smartcut.movieflow.ai/ai-editor/${projectId}?token=${token}&user_id=${userId}&auto=true&embedded=true`; + const aiEditingUrl = `${cutUrl}/ai-editor/${projectId}?token=${token}&user_id=${userId}&auto=true&embedded=true`; /** * 监听iframe消息 @@ -102,7 +104,7 @@ export const AIEditingIframe = React.forwardRef { const handleMessage = (event: MessageEvent) => { // 验证消息来源 - if (!event.origin.includes('smartcut.movieflow.ai')) { + if (!event.origin.includes(cutUrl)) { return; } diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index 766eb0d..ace46c5 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -21,6 +21,9 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = const useid = JSON.parse(localStorage.getItem("currentUser") || '{}').id || NaN; const notificationKey = useMemo(() => `video-workflow-${episodeId}`, [episodeId]); + const cutUrl = process.env.NEXT_PUBLIC_CUT_URL || 'https://cut.movieflow.ai'; + console.log('cutUrl', cutUrl); + useEffect(() => { console.log("init-useWorkflowData"); return () => { @@ -196,7 +199,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = }, [episodeId, onEditPlanGenerated, notificationKey]); const openEditPlan = useCallback(async () => { - window.open(`https://smartcut.movieflow.ai/ai-editor/${episodeId}?token=${token}&user_id=${useid}`, '_target'); + window.open(`${cutUrl}/ai-editor/${episodeId}?token=${token}&user_id=${useid}`, '_target'); }, [episodeId]); useEffect(() => { From 9c5d064bd7303bcda36f17378d49e7dda941987f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 23:26:45 +0800 Subject: [PATCH 12/20] =?UTF-8?q?=E5=88=A0=E6=8E=89=20=E5=85=B6=E4=BB=96co?= =?UTF-8?q?mpile=20=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- compile_mf.sh | 69 -------------------------------------------------- compile_pre.sh | 69 -------------------------------------------------- 2 files changed, 138 deletions(-) delete mode 100755 compile_mf.sh delete mode 100755 compile_pre.sh diff --git a/compile_mf.sh b/compile_mf.sh deleted file mode 100755 index a86f7fc..0000000 --- a/compile_mf.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -BRANCH_NAME="dev" - -# 修改项目名称 -PROJECT_NAME="video-flow-frontend" - -# 设置日志文件路径 -LOGFILE="build_and_copy.log" - -# 记录开始时间 -echo "Build process started at $(date)" | tee $LOGFILE - -# 获取当前分支名 -current_branch=$(git rev-parse --abbrev-ref HEAD) - -# 打包之前,需要检查是否在 dev 分支,工作区是否干净,是否和远程分支一致 -if [ "$(git branch --show-current)" != "$BRANCH_NAME" ]; then - echo "当前分支不是 dev 分支" - exit 1 -fi - -# 检查工作区是否干净 -if [ -n "$(git status --porcelain)" ]; then - echo "工作区不干净" - exit 1 -fi - -# 检查远程分支是否和本地分支一致 -if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/$BRANCH_NAME)" ]; then - echo "本地分支和远程分支不一致" - exit 1 -fi - - -# 检查当前分支并运行相应的 npm 命令 -if [ "$current_branch" = "$BRANCH_NAME" ]; then - echo "On dev branch, building project..." | tee -a $LOGFILE - PROFILE_ENV=$BRANCH_NAME - - # 安装依赖并构建 - yarn install - yarn build - - # 准备dist目录 - mkdir -p dist - cp -r .next dist/ - cp -r public dist/ - cp package.json dist/ - cp package-lock.json dist/ - -else - echo "On non-dev branch ($current_branch), exiting" - exit 1 -fi - -# 创建tar包 -tar -czvf $PROJECT_NAME-$PROFILE_ENV.tar.gz dist - -# 记录结束时间 -echo "Build process completed at $(date)" | tee -a $LOGFILE - -# 上传到 nexus -echo "upload to nexus at $(date)" | tee -a $LOGFILE -curl -u 'admin':'YZ9Gq6=8\*G|?:,' --upload-file $PROJECT_NAME-$PROFILE_ENV.tar.gz https://repo.qikongjian.com/repository/frontend-tar-files/ - -# 清理构建文件 -rm -rf dist -rm $PROJECT_NAME-$PROFILE_ENV.tar.gz diff --git a/compile_pre.sh b/compile_pre.sh deleted file mode 100755 index 22b2adc..0000000 --- a/compile_pre.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -BRANCH_NAME="dev" - -# 修改项目名称 -PROJECT_NAME="video-flow-$BRANCH_NAME-frontend" - -# 设置日志文件路径 -LOGFILE="build_and_copy.log" - -# 记录开始时间 -echo "Build process started at $(date)" | tee $LOGFILE - -# 获取当前分支名 -current_branch=$(git rev-parse --abbrev-ref HEAD) - -# 打包之前,需要检查是否在 dev 分支,工作区是否干净,是否和远程分支一致 -if [ "$(git branch --show-current)" != "$BRANCH_NAME" ]; then - echo "当前分支不是 dev 分支" - exit 1 -fi - -# 检查工作区是否干净 -if [ -n "$(git status --porcelain)" ]; then - echo "工作区不干净" - exit 1 -fi - -# 检查远程分支是否和本地分支一致 -if [ "$(git rev-parse HEAD)" != "$(git rev-parse origin/$BRANCH_NAME)" ]; then - echo "本地分支和远程分支不一致" - exit 1 -fi - - -# 检查当前分支并运行相应的 npm 命令 -if [ "$current_branch" = "$BRANCH_NAME" ]; then - echo "On dev branch, building project..." | tee -a $LOGFILE - PROFILE_ENV=$BRANCH_NAME - - # 安装依赖并构建 - yarn install - yarn build - - # 准备dist目录 - mkdir -p dist - cp -r .next dist/ - cp -r public dist/ - cp package.json dist/ - cp package-lock.json dist/ - -else - echo "On non-dev branch ($current_branch), exiting" - exit 1 -fi - -# 创建tar包 -tar -czvf $PROJECT_NAME-$PROFILE_ENV.tar.gz dist - -# 记录结束时间 -echo "Build process completed at $(date)" | tee -a $LOGFILE - -# 上传到 nexus -echo "upload to nexus at $(date)" | tee -a $LOGFILE -curl -u 'admin':'YZ9Gq6=8\*G|?:,' --upload-file $PROJECT_NAME-$PROFILE_ENV.tar.gz https://repo.qikongjian.com/repository/frontend-tar-files/ - -# 清理构建文件 -rm -rf dist -rm $PROJECT_NAME-$PROFILE_ENV.tar.gz From 260ce49cda0bdef661c0484ad523a196dc93a128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sat, 6 Sep 2025 23:57:13 +0800 Subject: [PATCH 13/20] =?UTF-8?q?mock=20=E7=99=BE=E7=A7=91=E5=85=A8?= =?UTF-8?q?=E4=B9=A6=E6=A8=A1=E7=89=88=20=E6=94=AF=E6=8C=81=E8=BE=93?= =?UTF-8?q?=E5=85=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Interaction/templateStoryService.ts | 11 ++- app/service/domain/Entities.ts | 9 +++ components/ChatInputBox/ChatInputBox.tsx | 68 ++++++++++++++++++- components/pages/work-flow/media-viewer.tsx | 1 + 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/app/service/Interaction/templateStoryService.ts b/app/service/Interaction/templateStoryService.ts index 89dacc4..c946d4b 100644 --- a/app/service/Interaction/templateStoryService.ts +++ b/app/service/Interaction/templateStoryService.ts @@ -68,6 +68,15 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => { setIsLoading(true); const templates = await templateStoryUseCase.getTemplateStoryList(); + templates.forEach(template => { + if (template.template_id === '69') { + template.freeInputItem = { + user_tips: "How is coffee made?", + constraints: "", + free_input_text: "" + }; + } + }); setTemplateStoryList(templates); setSelectedTemplate(templates[0]); @@ -237,7 +246,7 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => { setIsLoading(true); const params: CreateMovieProjectV3Request = { - script: selectedTemplate?.generateText || "", + script: selectedTemplate?.freeInputItem?.free_input_text || selectedTemplate?.generateText || "", category: selectedTemplate?.category || "", user_id, mode, diff --git a/app/service/domain/Entities.ts b/app/service/domain/Entities.ts index da780fd..0f26ff8 100644 --- a/app/service/domain/Entities.ts +++ b/app/service/domain/Entities.ts @@ -172,4 +172,13 @@ export interface StoryTemplateEntity { /** 道具照片URL */ photo_url: string; }[]; + /** 自由输入文字 */ + freeInputItem?: { + /** 用户提示,提示给用户需要输入什么内容 */ + user_tips: string; + /** 约束,可选,用于传给ai,让ai去拦截用户不符合约束的输入内容 */ + constraints: string; + /** 自由输入文字 */ + free_input_text: string; + } } diff --git a/components/ChatInputBox/ChatInputBox.tsx b/components/ChatInputBox/ChatInputBox.tsx index c32b6e0..a0113b7 100644 --- a/components/ChatInputBox/ChatInputBox.tsx +++ b/components/ChatInputBox/ChatInputBox.tsx @@ -46,6 +46,24 @@ import { HighlightEditor } from "../common/HighlightEditor"; import GlobalLoad from "../common/GlobalLoad"; /**模板故事模式弹窗组件 */ +/** + * 防抖函数 + * @param {Function} func - 需要防抖的函数 + * @param {number} wait - 等待时间(ms) + * @returns {Function} - 防抖后的函数 + */ +const debounce = (func: Function, wait: number) => { + let timeout: NodeJS.Timeout; + return function executedFunction(...args: any[]) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; +}; + const RenderTemplateStoryMode = ({ isTemplateCreating, setIsTemplateCreating, @@ -93,6 +111,22 @@ const RenderTemplateStoryMode = ({ clearData, } = useTemplateStoryServiceHook(); + // 防抖处理的输入更新函数 + const debouncedUpdateInput = debounce((value: string) => { + // 过滤特殊字符 + const sanitizedValue = value.replace(/[<>]/g, ''); + // 更新输入值 + if (!selectedTemplate?.freeInputItem) return; + const updatedTemplate: StoryTemplateEntity = { + ...selectedTemplate, + freeInputItem: { + ...selectedTemplate.freeInputItem, + free_input_text: sanitizedValue + } + }; + setSelectedTemplate(updatedTemplate); + }, 300); // 300ms 的防抖延迟 + // 使用上传文件hook const { uploadFile, isUploading } = useUploadFile(); // 本地加载状态,用于 UI 反馈 @@ -258,6 +292,7 @@ const RenderTemplateStoryMode = ({ + {/* 角色配置区域 */} {selectedTemplate?.storyRole && selectedTemplate.storyRole.length > 0 && ( @@ -755,7 +790,38 @@ const RenderTemplateStoryMode = ({ */} -
+
+ {/** 自由输入文字 */} + {(selectedTemplate?.freeInputItem) && ( +
+ { + const value = e.target.value; + // 限制输入长度为500字符 + if (value.length > 500) { + return; + } + // 立即更新UI显示 + if (!selectedTemplate?.freeInputItem) return; + const updatedTemplate: StoryTemplateEntity = { + ...selectedTemplate, + freeInputItem: { + ...selectedTemplate.freeInputItem, + free_input_text: value + } + }; + setSelectedTemplate(updatedTemplate); + // 使用防抖函数处理实际的状态更新 + debouncedUpdateInput(value); + }} + maxLength={500} + /> +
+ )} 0} handleCreateVideo={handleConfirm} diff --git a/components/pages/work-flow/media-viewer.tsx b/components/pages/work-flow/media-viewer.tsx index 419f9ed..9f0f90f 100644 --- a/components/pages/work-flow/media-viewer.tsx +++ b/components/pages/work-flow/media-viewer.tsx @@ -427,6 +427,7 @@ export const MediaViewer = React.memo(function MediaViewer({ // 渲染视频内容 const renderVideoContent = (onGotoCut: () => void) => { + if (!taskObject.videos.data[currentSketchIndex]) return null; const urls = taskObject.videos.data[currentSketchIndex]?.urls ? taskObject.videos.data[currentSketchIndex]?.urls.join(',') : ''; return (
Date: Sun, 7 Sep 2025 00:18:07 +0800 Subject: [PATCH 14/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E8=BE=93=E5=85=A5?= =?UTF-8?q?=E6=A1=86=20=E4=B8=AD=E6=96=87=E8=BE=93=E5=85=A5=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/ChatInputBox/ChatInputBox.tsx | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/components/ChatInputBox/ChatInputBox.tsx b/components/ChatInputBox/ChatInputBox.tsx index a0113b7..7d18121 100644 --- a/components/ChatInputBox/ChatInputBox.tsx +++ b/components/ChatInputBox/ChatInputBox.tsx @@ -796,29 +796,20 @@ const RenderTemplateStoryMode = ({
{ - const value = e.target.value; - // 限制输入长度为500字符 - if (value.length > 500) { - return; - } - // 立即更新UI显示 - if (!selectedTemplate?.freeInputItem) return; - const updatedTemplate: StoryTemplateEntity = { - ...selectedTemplate, + // 更新自由输入文字字段 + const updatedTemplate = { + ...selectedTemplate!, freeInputItem: { - ...selectedTemplate.freeInputItem, - free_input_text: value + ...selectedTemplate!.freeInputItem, + free_input_text: e.target.value } }; - setSelectedTemplate(updatedTemplate); - // 使用防抖函数处理实际的状态更新 - debouncedUpdateInput(value); + setSelectedTemplate(updatedTemplate as StoryTemplateEntity); }} - maxLength={500} />
)} From 7467025d09f57744ef30ba50463f91b9e1c62c6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 7 Sep 2025 02:46:23 +0800 Subject: [PATCH 15/20] =?UTF-8?q?=E4=B8=AD=E6=96=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/pages/work-flow/use-workflow-data.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index ace46c5..76f80ba 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -150,8 +150,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = showEditingNotification({ key: notificationKey, description: 'Generating intelligent editing plan...', - successDescription: '剪辑计划生成完成', - timeoutDescription: '剪辑计划生成失败,请重试', + successDescription: 'Editing plan generated successfully.', + timeoutDescription: 'Editing plan generation failed. Please refresh and try again.', timeout: 3 * 60 * 1000 }); // 先停止轮询 @@ -170,8 +170,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = showEditingNotification({ key: notificationKey, isCompleted: true, - description: '正在生成剪辑计划...', - successDescription: '剪辑计划生成完成', + description: 'Generating intelligent editing plan...', + successDescription: 'Editing plan generated successfully.', timeout: 3000 }); setTimeout(() => { From f85187d1de949dc6614b47c6da911e9115e93305 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 7 Sep 2025 03:15:27 +0800 Subject: [PATCH 16/20] =?UTF-8?q?=E7=94=9F=E6=88=90=E5=89=AA=E8=BE=91?= =?UTF-8?q?=E8=AE=A1=E5=88=92=E5=A4=B1=E8=B4=A5=EF=BC=8C=E5=B0=9D=E8=AF=95?= =?UTF-8?q?=E9=87=8D=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- components/pages/work-flow/use-workflow-data.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index 76f80ba..4eb9ea6 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -204,10 +204,10 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = useEffect(() => { // 主动触发剪辑 - if (canGoToCut && taskObject.currentStage === 'video') { + if (canGoToCut && (taskObject.currentStage === 'video' || !isGenerateEditPlan)) { generateEditPlan(); } - }, [canGoToCut, taskObject.currentStage]); + }, [canGoToCut, taskObject.currentStage, isGenerateEditPlan]); useEffect(() => { if (isShowError) { From e6f849e0af3956d838df24fadb919559cbec1066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 7 Sep 2025 04:54:21 +0800 Subject: [PATCH 17/20] =?UTF-8?q?=E9=87=8D=E8=AF=95=20=E5=89=AA=E8=BE=91?= =?UTF-8?q?=E8=AE=A1=E5=88=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- api/video_flow.ts | 4 +-- components/pages/work-flow.tsx | 2 +- .../pages/work-flow/use-workflow-data.tsx | 34 ++++++++++++++----- 4 files changed, 29 insertions(+), 13 deletions(-) diff --git a/.env.development b/.env.development index 7409920..2878ea4 100644 --- a/.env.development +++ b/.env.development @@ -6,4 +6,4 @@ NEXT_PUBLIC_CUT_URL = https://smartcut.movieflow.ai # NEXT_PUBLIC_JAVA_URL = https://test.java.movieflow.ai # NEXT_PUBLIC_BASE_URL = https://test.video.movieflow.ai # 失败率 -NEXT_PUBLIC_ERROR_CONFIG = 0.2 \ No newline at end of file +NEXT_PUBLIC_ERROR_CONFIG = 0.5 \ No newline at end of file diff --git a/api/video_flow.ts b/api/video_flow.ts index e88b38d..a4f2cec 100644 --- a/api/video_flow.ts +++ b/api/video_flow.ts @@ -292,8 +292,8 @@ export const getRunningStreamData = async (data: { }; // 获取 生成剪辑计划 接口 -export const getGenerateEditPlan = async (data: GenerateEditPlanRequest): Promise> => { - return post>("/edit-plan/generate-by-project", data); +export const getGenerateEditPlan = async (data: GenerateEditPlanRequest): Promise> => { + return post>("/edit-plan/generate-by-project", data); }; /** diff --git a/components/pages/work-flow.tsx b/components/pages/work-flow.tsx index edd8e2f..0de4dad 100644 --- a/components/pages/work-flow.tsx +++ b/components/pages/work-flow.tsx @@ -60,7 +60,7 @@ const WorkFlow = React.memo(function WorkFlow() { showEditingNotification({ description: 'Performing intelligent editing...', successDescription: 'Editing successful', - timeoutDescription: 'Editing failed, please try again', + timeoutDescription: 'Editing failed. Please click the edit button to go to the smart editing platform.', timeout: 5 * 60 * 1000, key: editingNotificationKey.current, onFail: () => { diff --git a/components/pages/work-flow/use-workflow-data.tsx b/components/pages/work-flow/use-workflow-data.tsx index 4eb9ea6..99863aa 100644 --- a/components/pages/work-flow/use-workflow-data.tsx +++ b/components/pages/work-flow/use-workflow-data.tsx @@ -76,6 +76,8 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = const [isShowError, setIsShowError] = useState(false); const [isAnalyzing, setIsAnalyzing] = useState(false); const [isGenerateEditPlan, setIsGenerateEditPlan] = useState(false); + const [retryCount, setRetryCount] = useState(0); + const [isLoadingGenerateEditPlan, setIsLoadingGenerateEditPlan] = useState(false); const [state, setState] = useState({ mode: 'automatic' as 'automatic' | 'manual' | 'auto', originalText: '', @@ -137,7 +139,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = } }, [taskObject.currentStage]); - const generateEditPlan = useCallback(async () => { + const generateEditPlan = useCallback(async (retryCount: number) => { if (isLoadedRef.current) { return; } @@ -149,7 +151,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = // 更新通知内容 showEditingNotification({ key: notificationKey, - description: 'Generating intelligent editing plan...', + description: `Generating intelligent editing plan... ${retryCount ? 'Retry Time: ' + retryCount : ''}`, successDescription: 'Editing plan generated successfully.', timeoutDescription: 'Editing plan generation failed. Please refresh and try again.', timeout: 3 * 60 * 1000 @@ -159,8 +161,13 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = setNeedStreamData(false); resolve(true); }); + setIsLoadingGenerateEditPlan(true); try { - await getGenerateEditPlan({ project_id: episodeId }); + const response = await getGenerateEditPlan({ project_id: episodeId }); + if (!response.data.editing_plan) { + throw new Error(response.message); + } + console.error('生成剪辑计划成功'); setIsGenerateEditPlan(true); isLoadedRef.current = 'true'; @@ -170,7 +177,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = showEditingNotification({ key: notificationKey, isCompleted: true, - description: 'Generating intelligent editing plan...', + description: `Generating intelligent editing plan... ${retryCount ? 'Retry Time: ' + retryCount : ''}`, successDescription: 'Editing plan generated successfully.', timeout: 3000 }); @@ -180,6 +187,7 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = // 触发回调,通知父组件计划生成完成 onEditPlanGenerated?.(); + setIsLoadingGenerateEditPlan(false); } catch (error) { console.error('生成剪辑计划失败:', error); setNeedStreamData(true); @@ -188,13 +196,14 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = // 显示失败通知3秒 showEditingNotification({ key: notificationKey, - description: '正在生成剪辑计划...', - timeoutDescription: '剪辑计划生成失败,请重试', + description: `Generating intelligent editing plan... ${retryCount ? 'Retry Time: ' + retryCount : ''}`, + timeoutDescription: 'Editing plan generation failed. Retrying later.', timeout: 3000 }); setTimeout(() => { notification.destroy(notificationKey); }, 3000); + setIsLoadingGenerateEditPlan(false); } }, [episodeId, onEditPlanGenerated, notificationKey]); @@ -204,10 +213,17 @@ export function useWorkflowData({ onEditPlanGenerated }: UseWorkflowDataProps = useEffect(() => { // 主动触发剪辑 - if (canGoToCut && (taskObject.currentStage === 'video' || !isGenerateEditPlan)) { - generateEditPlan(); + if (canGoToCut && taskObject.currentStage === 'video') { + generateEditPlan(retryCount); } - }, [canGoToCut, taskObject.currentStage, isGenerateEditPlan]); + }, [canGoToCut, taskObject.currentStage, retryCount]); + + useEffect(() => { + // 加载剪辑计划结束 并且 失败了 重试 + if (!isLoadingGenerateEditPlan && !isGenerateEditPlan) { + setRetryCount(retryCount + 1); + } + }, [isLoadingGenerateEditPlan, isGenerateEditPlan]); useEffect(() => { if (isShowError) { From 99f3002ff6f90e98c542cc653ea73cab938a19f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 7 Sep 2025 05:06:25 +0800 Subject: [PATCH 18/20] =?UTF-8?q?=E7=A7=AF=E5=88=86=E4=B8=8D=E8=B6=B3?= =?UTF-8?q?=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/errorHandle.ts | 7 +------ api/request.ts | 17 +++++++++++++++-- utils/notifications.tsx | 18 ++++++++++++++++-- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/api/errorHandle.ts b/api/errorHandle.ts index 2486b2d..fba0ba5 100644 --- a/api/errorHandle.ts +++ b/api/errorHandle.ts @@ -7,6 +7,7 @@ const HTTP_ERROR_MESSAGES: Record = { 0: "Please try again if the network is abnormal. If it happens again, please contact us.", 400: "Request parameter error, please check your input.", 401: "Login expired, please log in again.", + 402: "Insufficient points, please recharge.", 403: "Insufficient permissions to access this resource.", 404: "Requested resource does not exist.", 408: "Request timeout, please try again.", @@ -31,12 +32,6 @@ const ERROR_HANDLERS: Record void> = { localStorage.removeItem('token'); // 跳转到登录页面 window.location.href = '/login'; - }, - 4001: () => { - // 显示积分不足通知 - import('../utils/notifications').then(({ showInsufficientPointsNotification }) => { - showInsufficientPointsNotification(); - }); } }; diff --git a/api/request.ts b/api/request.ts index c30cc5a..f5f123f 100644 --- a/api/request.ts +++ b/api/request.ts @@ -10,11 +10,24 @@ import { errorHandle } from './errorHandle'; const handleRequestError = (error: any, defaultMessage: string = '请求失败') => { if (error.response) { const { status, data } = error.response; - const errorMessage = data?.message || defaultMessage; + const errorMessage = data?.message || data?.detail?.message || defaultMessage; + + // 处理 402 状态码的特殊情况 + if (status === 402 && data?.detail) { + import('./errorHandle').then(({ errorHandle }) => { + errorHandle(status, errorMessage); + // 调用积分不足通知,传入详细信息 + import('../utils/notifications').then(({ showInsufficientPointsNotification }) => { + showInsufficientPointsNotification(data.detail); + }); + }); + return; + } + errorHandle(status, errorMessage); } else if (error.request) { // 请求已发出但没有收到响应 - errorHandle(0 ); + errorHandle(0); } else { // 请求配置出错 errorHandle(0, error.message || defaultMessage); diff --git a/utils/notifications.tsx b/utils/notifications.tsx index a516df2..d7dda08 100644 --- a/utils/notifications.tsx +++ b/utils/notifications.tsx @@ -58,7 +58,11 @@ const btnStyle = { * 显示积分不足通知 * @description 在右上角显示一个带有充值链接的积分不足提醒 */ -export const showInsufficientPointsNotification = () => { +export const showInsufficientPointsNotification = (detail?: { + current_balance?: number; + required_tokens?: number; + message?: string; +}) => { notification.warning({ message: null, description: ( @@ -66,7 +70,17 @@ export const showInsufficientPointsNotification = () => {

Insufficient credits reminder

-

Your credits are insufficient, please upgrade to continue.

+

+ {detail?.message || 'Your credits are insufficient, please upgrade to continue.'} + {detail?.current_balance !== undefined && detail?.required_tokens !== undefined && ( + <> +
+ + Current balance: {detail.current_balance} / Required: {detail.required_tokens} + + + )} +

*/} diff --git a/utils/notifications.tsx b/utils/notifications.tsx index d7dda08..db8e313 100644 --- a/utils/notifications.tsx +++ b/utils/notifications.tsx @@ -90,7 +90,7 @@ export const showInsufficientPointsNotification = (detail?: {
), - duration: 5, + duration: 0, placement: 'topRight', style: darkGlassStyle, className: 'dark-glass-notification', From 608e7bf814420a4d8c8a3f110ff68d7112528d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=97=E6=9E=B3?= <7854742+wang_rumeng@user.noreply.gitee.com> Date: Sun, 7 Sep 2025 05:33:46 +0800 Subject: [PATCH 20/20] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E7=A7=AF=E5=88=86?= =?UTF-8?q?=E4=B8=8D=E8=B6=B3=E5=BC=B9=E7=AA=97=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/request.ts | 14 +++++--------- utils/notifications.tsx | 4 ++++ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/request.ts b/api/request.ts index f5f123f..4bc2b41 100644 --- a/api/request.ts +++ b/api/request.ts @@ -14,24 +14,20 @@ const handleRequestError = (error: any, defaultMessage: string = '请求失败') // 处理 402 状态码的特殊情况 if (status === 402 && data?.detail) { - import('./errorHandle').then(({ errorHandle }) => { - errorHandle(status, errorMessage); - // 调用积分不足通知,传入详细信息 - import('../utils/notifications').then(({ showInsufficientPointsNotification }) => { - showInsufficientPointsNotification(data.detail); - }); + // 只显示通知,不调用 errorHandle + import('../utils/notifications').then(({ showInsufficientPointsNotification }) => { + showInsufficientPointsNotification(data.detail); }); - return; + return; // 直接返回,不再抛出错误 } errorHandle(status, errorMessage); } else if (error.request) { - // 请求已发出但没有收到响应 errorHandle(0); } else { - // 请求配置出错 errorHandle(0, error.message || defaultMessage); } + return Promise.reject(error); // 将 reject 移到这里,避免 402 时重复处理 }; // 创建 axios 实例 const request: AxiosInstance = axios.create({ diff --git a/utils/notifications.tsx b/utils/notifications.tsx index db8e313..a44bbcd 100644 --- a/utils/notifications.tsx +++ b/utils/notifications.tsx @@ -63,7 +63,11 @@ export const showInsufficientPointsNotification = (detail?: { required_tokens?: number; message?: string; }) => { + // 生成唯一的 key + const key = `insufficient-points-${Date.now()}`; + notification.warning({ + key, // 添加唯一的 key message: null, description: (