From 3019383c5e7c59ba6766ac59a5381f6c91d6dc03 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, 29 Aug 2025 02:49:48 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E8=AF=B7=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/request.ts | 2 +- api/video_flow.ts | 45 +--- components/pages/login.tsx | 2 +- components/pages/work-flow/use-api-data.ts | 273 --------------------- next.config.js | 1 + 5 files changed, 14 insertions(+), 309 deletions(-) delete mode 100644 components/pages/work-flow/use-api-data.ts diff --git a/api/request.ts b/api/request.ts index c0c4491..e962187 100644 --- a/api/request.ts +++ b/api/request.ts @@ -34,7 +34,7 @@ const request: AxiosInstance = axios.create({ request.interceptors.request.use( (config: InternalAxiosRequestConfig) => { // 从 localStorage 获取 token - const token = localStorage?.getItem('token') || 'mock-token'; + const token = localStorage?.getItem('token'); if (token && config.headers) { (config.headers as AxiosHeaders).set('Authorization', `Bearer ${token}`); } diff --git a/api/video_flow.ts b/api/video_flow.ts index 194d2fe..f37c65c 100644 --- a/api/video_flow.ts +++ b/api/video_flow.ts @@ -269,52 +269,29 @@ export const getRunningStreamData = async (data: { return post>("/movie/get_status", data); }; -// 新增:获取项目任务列表接口(优化版本) +/** + * 获取项目任务列表接口 + * @param data - 请求参数 + * @param data.project_id - 项目ID + * @returns Promise> - 任务列表响应 + */ export const getProjectTaskList = async (data: { project_id: string; }): Promise> => { - const fullUrl = "https://77.smartvideo.py.qikongjian.com/task/get_project_task_list"; - - // 添加请求超时控制 - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), 30000); // 30秒超时 + const startTime = Date.now(); + console.log(`[API] 开始请求任务列表,项目ID: ${data.project_id}`); try { - console.log(`[API] 开始请求任务列表,项目ID: ${data.project_id}`); - const startTime = Date.now(); - - const response = await fetch(fullUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${localStorage?.getItem('token') || 'mock-token'}`, - }, - body: JSON.stringify(data), - signal: controller.signal, // 添加超时控制 - }); - - clearTimeout(timeoutId); + const result = await post>('/task/get_project_task_list', data); + const endTime = Date.now(); console.log(`[API] 请求完成,耗时: ${endTime - startTime}ms`); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const result = await response.json(); console.log(`[API] 数据解析完成,任务数量: ${Array.isArray(result.data) ? result.data.length : 0}`); return result; } catch (error) { - clearTimeout(timeoutId); - - if (error instanceof Error && error.name === 'AbortError') { - console.error('[API] 请求超时 (30秒)'); - throw new Error('请求超时,请检查网络连接'); - } - console.error('[API] 获取任务列表失败:', error); - throw error instanceof Error ? error : new Error('未知错误'); + throw error; } }; diff --git a/components/pages/login.tsx b/components/pages/login.tsx index 4f9e637..b964236 100644 --- a/components/pages/login.tsx +++ b/components/pages/login.tsx @@ -57,7 +57,7 @@ export default function Login() { // 根据错误类型显示不同的错误消息 setFormError( - "Login failed, please check your credentials and try again." + "Login failed, please try again." ); } finally { setIsSubmitting(false); diff --git a/components/pages/work-flow/use-api-data.ts b/components/pages/work-flow/use-api-data.ts deleted file mode 100644 index 15337c3..0000000 --- a/components/pages/work-flow/use-api-data.ts +++ /dev/null @@ -1,273 +0,0 @@ -import { useState, useEffect, useCallback } from 'react'; -import { detailScriptEpisodeNew, getScriptTitle, getRunningStreamData, StreamData } from '@/api/video_flow'; -import { useSearchParams } from 'next/navigation'; -import { ApiResponse } from '@/api/common'; -import { SketchData, CharacterResponse, VideoData } from '@/api/DTO/movieEdit'; - -// 步骤映射 -const STEP_MAP = { - 'sketch': '1', - 'character': '2', - 'video': '3', - 'music': '4', - 'final_video': '6' -} as const; - -type ApiStep = keyof typeof STEP_MAP; - -interface TaskData { - sketch?: { - url: string; - script: string; - bg_rgb: string[]; - }[]; - roles?: { - name: string; - url: string; - sound: string; - soundDescription: string; - roleDescription: string; - }[]; - videos?: { - url: string; - script: string; - audio: string; - }[]; - music?: { - url: string; - script: string; - name: string; - duration: string; - totalDuration: string; - isLooped: boolean; - }[]; - final?: { - url: string; - }; - [key: string]: any; // 允许其他可能的字段 -} - -export const useApiData = () => { - const searchParams = useSearchParams(); - const episodeId = searchParams.get('episodeId'); - - const [title, setTitle] = useState(''); - const [currentStep, setCurrentStep] = useState('1'); - const [currentLoadingText, setCurrentLoadingText] = useState(''); - const [needStreamData, setNeedStreamData] = useState(false); - const [taskData, setTaskData] = useState({}); - const [streamInterval, setStreamInterval] = useState(null); - - // 处理流式数据 - const handleStreamData = useCallback((streamData: ApiResponse) => { - const { category, message, data, status } = streamData.data; - - // 更新加载文本 - setCurrentLoadingText(message); - - // 根据类别更新任务数据 - setTaskData(prevData => { - const newData = { ...prevData }; - - switch (category) { - case 'sketch': - if (!newData.sketch) newData.sketch = []; - // 更新或追加分镜数据 - const existingSketchIndex = newData.sketch.findIndex(s => s.url === data.url); - if (existingSketchIndex === -1) { - newData.sketch.push(data); - } else { - newData.sketch[existingSketchIndex] = data; - } - break; - - case 'character': - if (!newData.roles) newData.roles = []; - // 更新或追加角色数据 - const existingRoleIndex = newData.roles.findIndex(r => r.name === data.name); - if (existingRoleIndex === -1) { - newData.roles.push(data); - } else { - newData.roles[existingRoleIndex] = data; - } - break; - - case 'video': - if (!newData.videos) newData.videos = []; - // 更新或追加视频数据 - const existingVideoIndex = newData.videos.findIndex(v => v.url === data.url); - if (existingVideoIndex === -1) { - newData.videos.push(data); - } else { - newData.videos[existingVideoIndex] = data; - } - break; - - case 'music': - if (!newData.music) newData.music = []; - newData.music = [data]; - break; - - case 'final_video': - newData.final = data; - break; - } - - return newData; - }); - - // 如果状态为 completed,停止获取流式数据 - if (status === 'completed' || streamData.data.all_completed) { - setNeedStreamData(false); - } - }, []); - - // 获取流式数据 - const fetchStreamData = useCallback(async () => { - if (!episodeId || !needStreamData) return; - - try { - const streamData = await getRunningStreamData({ project_id: episodeId }); - handleStreamData(streamData); - } catch (error) { - console.error('获取流式数据失败:', error); - } - }, [episodeId, needStreamData, handleStreamData]); - - // 启动流式数据轮询 - useEffect(() => { - if (needStreamData && !streamInterval) { - const interval = setInterval(fetchStreamData, 10000); // 修改为10秒 - setStreamInterval(interval); - } else if (!needStreamData && streamInterval) { - clearInterval(streamInterval); - setStreamInterval(null); - } - - return () => { - if (streamInterval) { - clearInterval(streamInterval); - } - }; - }, [needStreamData, fetchStreamData, streamInterval]); - - // 获取标题的轮询函数 - const pollTitle = useCallback(async () => { - if (!episodeId) return; - - try { - const response = await getScriptTitle({ project_id: episodeId }); - if (response.successful && response.data) { - setTitle(response.data.name); - return true; - } - } catch (error) { - console.error('获取标题失败:', error); - } - return false; - }, [episodeId]); - - // 获取剧集详情 - const fetchEpisodeDetail = useCallback(async () => { - if (!episodeId) return; - - try { - const response = await detailScriptEpisodeNew({ project_id: episodeId }); - if (response.successful) { - const { name, status, step, last_message, data } = response.data; - - // 设置标题 - if (name) { - setTitle(name); - } - - // 设置步骤 - if (step && STEP_MAP[step as ApiStep]) { - setCurrentStep(STEP_MAP[step as ApiStep]); - } - - // 设置加载文本 - setCurrentLoadingText(last_message || ''); - - // 设置是否需要流式数据 - setNeedStreamData(status === 'running'); - - // 设置任务数据 - if (data) { - // 将 ProjectContentData 转换为 TaskData - const convertedData: TaskData = { - sketch: data.sketch?.data?.map((item: SketchData) => ({ - url: item.image_path, - script: item.prompt, - bg_rgb: ['255', '255', '255'] // 默认白色背景 - })) || [], - roles: data.character?.data?.map((item: CharacterResponse) => ({ - name: item.character_name, - url: item.image_path, - sound: '', - soundDescription: '', - roleDescription: item.character_description - })) || [], - videos: data.video?.data?.map((item: VideoData) => ({ - url: item.urls?.[0] || '', - script: item.description || '', - audio: '' // 音频URL可能需要从其他地方获取 - })) || [], - music: data.music?.data?.map((item: any) => ({ - url: item.url || '', - script: item.description || '', - name: item.name || '', - duration: item.duration || '', - totalDuration: item.total_duration || '', - isLooped: item.is_looped || false - })) || [], - final: data.final_video ? { - url: data.final_video.video || '' - } : undefined - }; - setTaskData(convertedData); - } - - return true; - } - } catch (error) { - console.error('获取剧集详情失败:', error); - } - return false; - }, [episodeId]); - - // 初始化数据 - useEffect(() => { - let titleInterval: NodeJS.Timeout; - - const initData = async () => { - const detailSuccess = await fetchEpisodeDetail(); - - // 如果详情接口没有返回标题,开始轮询标题 - if (detailSuccess && !title) { - titleInterval = setInterval(async () => { - const success = await pollTitle(); - if (success) { - clearInterval(titleInterval); - } - }, 3000); - } - }; - - initData(); - - return () => { - if (titleInterval) { - clearInterval(titleInterval); - } - }; - }, [episodeId, fetchEpisodeDetail, pollTitle, title]); - - return { - title, - currentStep, - currentLoadingText, - needStreamData, - taskData - }; -}; \ No newline at end of file diff --git a/next.config.js b/next.config.js index dce7dad..3159550 100644 --- a/next.config.js +++ b/next.config.js @@ -36,6 +36,7 @@ const nextConfig = { async rewrites() { // 使用环境变量,如果没有则使用默认值 const BASE_URL = process.env.NEXT_PUBLIC_BASE_URL || 'https://77.smartvideo.py.qikongjian.com' + // const BASE_URL = 'http://192.168.120.5:8000' return [ { source: '/api/proxy/:path*', From 99b8c9b474452cb445b4215a119d90d9d84e6e82 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, 29 Aug 2025 03:18:20 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=B8=AD=E6=96=87=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/movie_queue.ts | 4 +- app/api/stream/route.ts | 112 --- app/layout.tsx | 2 - app/model/enums.ts | 100 +-- app/payment-success/page.tsx | 46 +- app/pricing/page.tsx | 2 +- app/service/adapter/oldErrAdapter.ts | 4 +- components/QueueBox/QueueNotification.tsx | 183 ---- components/QueueBox/QueueNotification2.tsx | 6 +- components/QueueBox/queue-notification.tsx | 209 ----- components/ai-suggestion-bar.tsx | 225 ----- components/filmstrip-stepper.tsx | 224 ----- components/ui/CharacterToken.tsx | 8 +- components/ui/character-library-selector.tsx | 2 +- components/ui/character-tab-content.tsx | 8 +- components/ui/edit-modal.tsx | 2 +- components/ui/script-tab-content.tsx | 2 +- components/workflow/add-music-step.tsx | 317 ------- .../workflow/final-composition-step.tsx | 288 ------ .../workflow/generate-chapters-step.tsx | 226 ----- components/workflow/generate-shots-step.tsx | 836 ------------------ components/workflow/input-script-step.tsx | 416 --------- components/workflow/work-office/mock-data.ts | 2 +- 23 files changed, 45 insertions(+), 3179 deletions(-) delete mode 100644 app/api/stream/route.ts delete mode 100644 components/QueueBox/QueueNotification.tsx delete mode 100644 components/QueueBox/queue-notification.tsx delete mode 100644 components/ai-suggestion-bar.tsx delete mode 100644 components/filmstrip-stepper.tsx delete mode 100644 components/workflow/add-music-step.tsx delete mode 100644 components/workflow/final-composition-step.tsx delete mode 100644 components/workflow/generate-chapters-step.tsx delete mode 100644 components/workflow/generate-shots-step.tsx delete mode 100644 components/workflow/input-script-step.tsx diff --git a/api/movie_queue.ts b/api/movie_queue.ts index 6e95690..273da29 100644 --- a/api/movie_queue.ts +++ b/api/movie_queue.ts @@ -84,7 +84,7 @@ export async function withQueuePolling( const poll = async (): Promise => { try { if (isCancelled) { - throw new Error('操作已取消'); + throw new Error('Operation canceled'); } const response = await apiCall(params); @@ -110,7 +110,7 @@ export async function withQueuePolling( // 检查是否达到最大尝试次数 if (attempts >= maxAttempts) { notification.destroy(); // 关闭通知 - throw new Error('超过最大轮询次数限制'); + throw new Error('Exceeded the maximum polling limit'); } // 继续轮询 diff --git a/app/api/stream/route.ts b/app/api/stream/route.ts deleted file mode 100644 index 269c1e6..0000000 --- a/app/api/stream/route.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { parseMDXContent } from '@/lib/mdx'; -import { BASE_URL } from '@/api/constants'; - -export const dynamic = 'force-dynamic'; -export const runtime = 'edge'; - -export async function GET() { - try { - const content = `[分析场景核心]: 一位舞者对完美的执念,使她的美丽舞蹈转化为一种自我毁灭的仪式。 - -### 第一幕:开端 - -内景 · 舞蹈室 - 傍晚 - -夕阳透过窗户,阳光携带着飞舞的尘埃,划出一块金色矩形洒在斑驳的木地板上。墙面苍白、剥落。一整面落地镜映出这空旷房间的寂静。 - -ELARA(20岁出头),身姿优雅至极,立于光影正中。她赤脚,穿着一件简单的黑色紧身舞衣,随着一段大提琴独奏起舞——旋律哀伤而高昂。 - -她的身体如流水般线条优雅。一只手臂伸展,手指在空气中描绘出无形的轨迹。她缓缓旋转,像是违抗了重力的引力。在这一刻,她是完美的化身。 - -但她的双眼,始终盯着镜中的自己,突然微微眯起——一丝自我厌弃的情绪一闪而过那个旋转,不够纯净。不够完美。对她而言。 - -她打断了舞姿。现在,她的呼吸变得可闻,如利刃般切入大提琴的温柔旋律。 - -她毫不迟疑地重新起舞。这一次,更快、更狠。舞姿仍美,却变得尖锐,带着绝望的锋芒。 - -一滴汗水,从她的太阳穴滑落。 - -她再次旋转,又旋转。一个狂热、残酷的段落。她的脸不再沉静,而是绷紧的面具,咬牙切齿。音乐愈发高亢,但我们所听见的,只有她脚步在木地板上滑出的尖锐声响,以及她粗重、急促的喘息。 - -镜中的倒影已模糊成一道疯狂的涂抹。她强迫自己再做一个旋转——那种超越极限的最后一圈。 - -她的脚踝崩溃了。 - -不是咔嚓断裂的声响,而是一种沉默、恶心的扭曲。Elara 倒在地上,如阳光外的一团残骸,四肢交错,失去光环。 - -大提琴继续演奏,平静、冷漠。 - -她喉间发出一声哽咽般的呜咽,是房间中唯一的声音。镜头穿过她起伏的肩膀,聚焦她的脚——足弓紧绷,脚趾青紫,地板上划出一丝血痕。 - -### 导演与表演附录 - -【导演风格解码】 -• 核心视觉基调: 高反差明暗对比,采用单一自然光源(窗户)。随着角色状态的恶化,色调从温暖金色逐渐转为冷峻的蓝灰。 -• 关键镜头处理建议: 开始用宽阔流畅的镜头呼应舞者的优雅;当其内心破裂时,剪切到突兀的特写镜头:颤抖的大腿肌肉、颈侧汗珠、扭曲的表情与模糊的镜中倒影。最后一个镜头采用固定机位,锁定她瘫倒的身体,强化突然静止的冲击感。她的舞步原本是以光影为中心的循环,她的倒地打破了这一循环,使她落入阴影。 - -### 核心表演关键 - -• 角色肢体表现: 表演需呈现双重性——外在看似毫不费力的优雅与内在痛苦的微妙细节同在。崩溃时不应夸张,而应如过度拉紧的身体对重力的安静屈服。 -• 潜台词驱动: 这是与"无形评审"——镜中自己——之间的战争。每一个动作都是抗议,每一个旋转是一种恳求,每一次喘息都是诅咒。核心动机是:"我要强迫这个不完美的身体创造一个完美的瞬间,即使这将摧毁我。" - -### 当代表达的连接 - -这个故事呼应了当代数字时代"精心营造的完美主义"现象,在理想化的自我形象背后,隐藏着焦虑与倦怠的真实生活。 -`; - - console.log('开始解析 MDX 内容...'); - const chunks = await parseMDXContent(content); - console.log('解析完成,获得块数:', chunks?.length); - - if (!chunks || chunks.length === 0) { - console.error('没有生成有效的内容块'); - return new Response( - JSON.stringify({ error: '内容解析失败' }), - { - status: 500, - headers: { 'Content-Type': 'application/json' } - } - ); - } - - // 创建一个可写流来处理数据 - const stream = new TransformStream(); - const writer = stream.writable.getWriter(); - const encoder = new TextEncoder(); - - // 异步处理数据流 - (async () => { - try { - for (const chunk of chunks) { - const data = encoder.encode(JSON.stringify(chunk) + '\n'); - await writer.write(data); - } - } catch (error) { - console.error('写入流时出错:', error); - } finally { - await writer.close(); - } - })(); - - return new Response(stream.readable, { - headers: { - 'Content-Type': 'text/event-stream', - 'Cache-Control': 'no-cache, no-transform', - 'Connection': 'keep-alive', - }, - }); - - } catch (error) { - console.error('API 路由处理出错:', error); - return new Response( - JSON.stringify({ - error: '服务器处理请求时出错', - details: error instanceof Error ? error.message : '未知错误' - }), - { - status: 500, - headers: { 'Content-Type': 'application/json' } - } - ); - } -} \ No newline at end of file diff --git a/app/layout.tsx b/app/layout.tsx index 5464391..35607f6 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -3,8 +3,6 @@ import './globals.css'; import { createContext, useContext, useEffect, useState } from 'react'; import { Providers } from '@/components/providers'; import { ConfigProvider, theme } from 'antd'; -import { createScreenAdapter } from '@/utils/tools'; -import { ScreenAdapter } from './ScreenAdapter'; import CallbackModal from '@/components/common/CallbackModal'; // 创建上下文来传递弹窗控制方法 diff --git a/app/model/enums.ts b/app/model/enums.ts index 245737e..8981774 100644 --- a/app/model/enums.ts +++ b/app/model/enums.ts @@ -64,11 +64,11 @@ export const ProjectTypeMap = { export const ModeMap = { [ModeEnum.MANUAL]: { value: "manual", - label: "手动" + label: "Manual" }, [ModeEnum.AUTOMATIC]: { value: "automatic", - label: "自动" + label: "Automatic" } } as const; @@ -108,66 +108,6 @@ export const VideoDurationMap = { } } as const; -// 工作流阶段映射 -export const FlowStageMap = { - [FlowStageEnum.PREVIEW]: { - value: "preview", - label: "预览图列表分镜草图" - }, - [FlowStageEnum.CHARACTERS]: { - value: "characters", - label: "角色列表" - }, - [FlowStageEnum.SHOTS]: { - value: "shots", - label: "分镜视频列表" - }, - [FlowStageEnum.BGM]: { - value: "bgm", - label: "背景音乐列表" - }, - [FlowStageEnum.POST_PRODUCTION]: { - value: "post_production", - label: "后期操作中" - }, - [FlowStageEnum.MERGE_VIDEO]: { - value: "merge_video", - label: "合并视频完成" - }, - [FlowStageEnum.ERROR]: { - value: "error", - label: "出错" - } -} as const; - -// 任务状态映射 -export const TaskStatusMap = { - [TaskStatusEnum.PENDING]: { - value: "pending", - label: "待处理" - }, - [TaskStatusEnum.PROCESSING]: { - value: "processing", - label: "处理中" - }, - [TaskStatusEnum.COMPLETED]: { - value: "completed", - label: "已完成" - }, - [TaskStatusEnum.FAILED]: { - value: "failed", - label: "失败" - }, - [TaskStatusEnum.RETRYING]: { - value: "retrying", - label: "重试中" - }, - [TaskStatusEnum.CANCELLED]: { - value: "cancelled", - label: "已取消" - } -} as const; - // 分镜脚本编辑器类型定义 export interface StoryboardCard { id: string; @@ -221,39 +161,3 @@ export interface CharacterOption { age: string; description: string; } - -// Mock 数据 -export const mockSceneOptions: SceneOption[] = [ - { sceneId: '1', name: '暮色森林', image: 'https://c.huiying.video/images/7fd3f2d6-840a-46ac-a97d-d3d1b37ec4e0.jpg', location: '西境边陲', time: '傍晚' } -]; - -export const mockCharacterOptions: CharacterOption[] = [ - { characterId: '1', name: '艾琳', image: 'https://c.huiying.video/images/32f6b07c-bceb-4b63-8a13-4749703ab08d.jpg', gender: '女', age: '24', description: '银发女剑士' }, - { characterId: '2', name: '影子猎手', image: 'https://c.huiying.video/images/97c6c59a-50cc-4159-aacd-94ab9d208150.jpg', gender: '男', age: '35', description: '神秘追踪者' }, -]; - -export const mockStoryboards: StoryboardCard[] = [ - { - id: '1', - shotId: 'SC-01', - scene: mockSceneOptions[0], - characters: [mockCharacterOptions[0], mockCharacterOptions[1]], - description: '艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现艾琳警惕地穿过森林,影子猎手的身影若隐若现', - shotType: '中景', - cameraMove: '缓慢推进', - dialogues: [ - { id: 'd1', speaker: '艾琳', text: '我们必须在 #影子猎手# 到来前穿过 [暮色森林]。' }, - { id: 'd2', speaker: '影子猎手', text: '你以为能逃出这里?' }, - ], - notes: '镜头缓慢推进至人物背影', - }, -]; - -export const characterInfoMap: Record = { - '艾琳': { avatar: 'https://c.huiying.video/images/32f6b07c-bceb-4b63-8a13-4749703ab08d.jpg', gender: '女', age: '24', description: '银发女剑士' }, - '影子猎手': { avatar: 'https://c.huiying.video/images/97c6c59a-50cc-4159-aacd-94ab9d208150.jpg', gender: '男', age: '35', description: '神秘追踪者' }, -}; - -export const sceneInfoMap: Record = { - '暮色森林': { image: 'https://c.huiying.video/images/7fd3f2d6-840a-46ac-a97d-d3d1b37ec4e0.jpg', location: '西境边陲', time: '傍晚' }, -}; diff --git a/app/payment-success/page.tsx b/app/payment-success/page.tsx index 710ee99..59b9c12 100644 --- a/app/payment-success/page.tsx +++ b/app/payment-success/page.tsx @@ -80,16 +80,16 @@ export default function PaymentSuccessPage() {
- 处理中... + Processing... - 正在确认您的支付,请稍候 + Confirming your payment, please wait
- 尝试次数: {attempts}/30 + Attempts: {attempts}/30

- 请不要关闭此页面,我们正在处理您的订阅 + Please do not close this page, we are processing your subscription

@@ -102,32 +102,32 @@ export default function PaymentSuccessPage() {
- 支付成功! + Payment successful! - 您的订阅已激活 + Your subscription has been activated {paymentData?.subscription && (

- {paymentData.subscription.plan_display_name} 套餐 + {paymentData.subscription.plan_display_name} Plan

- 状态: {paymentData.subscription.status} + Status: {paymentData.subscription.status}

{paymentData.subscription.current_period_end && (

- 有效期至: {new Date(paymentData.subscription.current_period_end).toLocaleDateString()} + Valid until: {new Date(paymentData.subscription.current_period_end).toLocaleDateString()}

)}
)}
-

订单号: {paymentData?.biz_order_no}

+

Order number: {paymentData?.biz_order_no}

{paymentData?.pay_time && ( -

支付时间: {new Date(paymentData.pay_time).toLocaleString()}

+

Payment time: {new Date(paymentData.pay_time).toLocaleString()}

)}
@@ -136,14 +136,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.href = '/dashboard'} className="flex-1" > - 前往控制台 + Go to dashboard
@@ -157,14 +157,14 @@ export default function PaymentSuccessPage() {
- 支付失败 + Payment failed - 很抱歉,您的支付未能成功完成 + Sorry, your payment was not successful

- 请检查您的支付信息或稍后重试 + Please check your payment information or try again later

@@ -172,14 +172,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.href = '/pricing'} className="flex-1" > - 重新选择套餐 + Re-select plan
@@ -193,14 +193,14 @@ export default function PaymentSuccessPage() {
- 处理中 + Processing - 支付正在处理中,请稍后查看 + Payment is being processed, please check later

- 您的支付可能仍在处理中,请稍后检查您的订阅状态 + Your payment may still be processing, please check your subscription status later

@@ -208,14 +208,14 @@ export default function PaymentSuccessPage() { onClick={() => window.location.reload()} className="flex-1" > - 刷新页面 + Refresh page
diff --git a/app/pricing/page.tsx b/app/pricing/page.tsx index 660dd98..533b4e7 100644 --- a/app/pricing/page.tsx +++ b/app/pricing/page.tsx @@ -80,7 +80,7 @@ function HomeModule5() { const User = JSON.parse(localStorage.getItem("currentUser") || "{}"); if (!User.id) { - throw new Error("无法获取用户ID,请重新登录"); + throw new Error("Unable to obtain user ID, please log in again"); } // 1. 创建Checkout Session diff --git a/app/service/adapter/oldErrAdapter.ts b/app/service/adapter/oldErrAdapter.ts index 52f09a4..5fa328b 100644 --- a/app/service/adapter/oldErrAdapter.ts +++ b/app/service/adapter/oldErrAdapter.ts @@ -135,7 +135,7 @@ export class VideoSegmentEntityAdapter { // 如果没有任何镜头但有narrative_goal,将其作为镜头1 if (lens.length === 0 && result.narrative_goal) { - const narrativeLens = new LensType("镜头1", result.narrative_goal, []); + const narrativeLens = new LensType("shot_1", result.narrative_goal, []); lens.push(narrativeLens); } @@ -159,7 +159,7 @@ export class VideoSegmentEntityAdapter { // 创建VideoSegmentEntity const entity: VideoSegmentEntity = { id: `video_mock_${index}`, // 生成临时ID,包含索引 - name: `视频片段_${index}`, // 生成临时名称,包含索引 + name: `video_${index}`, // 生成临时名称,包含索引 sketchUrl: "", // 后端数据中没有sketchUrl,设为空字符串 videoUrl: result.videos, status: status, diff --git a/components/QueueBox/QueueNotification.tsx b/components/QueueBox/QueueNotification.tsx deleted file mode 100644 index e296513..0000000 --- a/components/QueueBox/QueueNotification.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import { notification } from 'antd'; - -const darkGlassStyle = { - background: 'rgba(30, 32, 40, 0.95)', - backdropFilter: 'blur(10px)', - WebkitBackdropFilter: 'blur(10px)', - border: '1px solid rgba(255, 255, 255, 0.08)', - borderRadius: '8px', - boxShadow: '0 4px 16px rgba(0, 0, 0, 0.4)', - padding: '12px 16px', -}; - -/** 胶片容器样式 */ -const filmStripContainerStyle = { - position: 'relative' as const, - width: '100%', - height: '80px', - marginBottom: '16px', - overflow: 'hidden', -}; - -/** 胶片样式 */ -const filmStripStyle = { - display: 'flex', - alignItems: 'center', - animation: 'filmScroll 20s linear infinite', -}; - -/** 文字样式 */ -const textStyle = { - fontSize: '13px', - color: 'rgba(255, 255, 255, 0.9)', - marginBottom: '12px', -}; - -/** 胶片帧组件 */ -const FilmFrame = () => ( -
- - {/* 胶片外框 */} - - {/* 齿孔 */} - - - - - {/* 胶片画面区域 */} - - -
-); - -/** 放映机音效组件 */ -const ProjectorSound = () => ( -