修复接口请求

This commit is contained in:
北枳 2025-08-29 02:49:48 +08:00
parent a5ea76a28e
commit 3019383c5e
5 changed files with 14 additions and 309 deletions

View File

@ -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}`);
}

View File

@ -269,52 +269,29 @@ export const getRunningStreamData = async (data: {
return post<ApiResponse<any>>("/movie/get_status", data);
};
// 新增:获取项目任务列表接口(优化版本)
/**
*
* @param data -
* @param data.project_id - ID
* @returns Promise<ApiResponse<TaskItem[]>> -
*/
export const getProjectTaskList = async (data: {
project_id: string;
}): Promise<ApiResponse<TaskItem[]>> => {
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<ApiResponse<TaskItem[]>>('/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;
}
};

View File

@ -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);

View File

@ -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<string>('');
const [currentStep, setCurrentStep] = useState<string>('1');
const [currentLoadingText, setCurrentLoadingText] = useState<string>('');
const [needStreamData, setNeedStreamData] = useState<boolean>(false);
const [taskData, setTaskData] = useState<TaskData>({});
const [streamInterval, setStreamInterval] = useState<NodeJS.Timeout | null>(null);
// 处理流式数据
const handleStreamData = useCallback((streamData: ApiResponse<StreamData>) => {
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
};
};

View File

@ -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*',