forked from 77media/video-flow
更新角色和视频任务的保存逻辑,重构SaveEditUseCase以支持角色和视频任务的管理,优化相关服务的接口调用。
This commit is contained in:
parent
2ab25bc72c
commit
7abf41a83d
@ -1108,8 +1108,13 @@ export const checkShotVideoStatus = async (request: {
|
||||
export const modifyCharacterOrScene = async (request: {
|
||||
/** 项目ID */
|
||||
project_id: string;
|
||||
/** 角色ID(可能为null) */
|
||||
character_id?: string | null;
|
||||
/** 新的角色库角色 */
|
||||
character_id: {
|
||||
/** 角色ID */
|
||||
character_id: string;
|
||||
/** 角色名称 */
|
||||
name: string;
|
||||
}[];
|
||||
/** 视频任务关联列表 */
|
||||
video_tasks: Array<{
|
||||
/** 生成视频的任务ID */
|
||||
@ -1117,30 +1122,7 @@ export const modifyCharacterOrScene = async (request: {
|
||||
/** 该任务对应的video_id列表 */
|
||||
video_ids: string[];
|
||||
}>;
|
||||
}): Promise<ApiResponse<{
|
||||
/** 项目ID */
|
||||
project_id: string;
|
||||
/** 自动检测到的修改类型("character" 或 "scene") */
|
||||
modify_type: "character" | "scene";
|
||||
/** 传入的视频任务列表 */
|
||||
video_tasks: Array<{
|
||||
task_id: string;
|
||||
video_ids: string[];
|
||||
}>;
|
||||
/** 处理结果描述 */
|
||||
message: string;
|
||||
/** 详细处理信息 */
|
||||
details: Record<string, any>;
|
||||
/** 警告信息(如有) */
|
||||
warning: string | null;
|
||||
/** 启动的视频检测任务列表 */
|
||||
video_check_tasks: Array<{
|
||||
task_id: string;
|
||||
video_ids: string[];
|
||||
}>;
|
||||
/** 启动的视频检测任务数量 */
|
||||
video_check_started: number;
|
||||
}>> => {
|
||||
}) => {
|
||||
return post<ApiResponse<{
|
||||
project_id: string;
|
||||
modify_type: "character" | "scene";
|
||||
|
||||
@ -1,8 +1,12 @@
|
||||
import { useState, useCallback, useMemo } from 'react';
|
||||
import { RoleEntity, AITextEntity } from '../domain/Entities';
|
||||
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
|
||||
import { getUploadToken, uploadToQiniu } from '@/api/common';
|
||||
import { analyzeImageDescription, checkShotVideoStatus } from '@/api/video_flow';
|
||||
import { useState, useCallback, useMemo } from "react";
|
||||
import { RoleEntity, AITextEntity } from "../domain/Entities";
|
||||
import { RoleEditUseCase } from "../usecase/RoleEditUseCase";
|
||||
import { getUploadToken, uploadToQiniu } from "@/api/common";
|
||||
import {
|
||||
analyzeImageDescription,
|
||||
checkShotVideoStatus,
|
||||
} from "@/api/video_flow";
|
||||
import { SaveEditUseCase } from "../usecase/SaveEditUseCase";
|
||||
|
||||
/**
|
||||
* 角色服务Hook返回值接口
|
||||
@ -52,11 +56,12 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
const [selectedRole, setSelectedRole] = useState<RoleEntity | null>(null);
|
||||
const [currentRoleText, setCurrentRoleText] = useState<string | null>(null);
|
||||
const [userRoleLibrary, setUserRoleLibrary] = useState<RoleEntity[]>([]);
|
||||
const [projectId, setProjectId] = useState<string>(''); // 添加项目ID状态
|
||||
const [projectId, setProjectId] = useState<string>(""); // 添加项目ID状态
|
||||
const [cacheRole, setCacheRole] = useState<RoleEntity | null>(null);
|
||||
|
||||
// UseCase实例 - 在角色选择时初始化
|
||||
const [roleEditUseCase, setRoleEditUseCase] = useState<RoleEditUseCase | null>(null);
|
||||
const [roleEditUseCase, setRoleEditUseCase] =
|
||||
useState<RoleEditUseCase | null>(null);
|
||||
|
||||
// 计算属性
|
||||
/**
|
||||
@ -64,7 +69,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
* @description 获取当前选中角色的图片URL
|
||||
*/
|
||||
const roleImageUrl = useMemo(() => {
|
||||
return selectedRole?.imageUrl || '';
|
||||
return selectedRole?.imageUrl || "";
|
||||
}, [selectedRole]);
|
||||
|
||||
/**
|
||||
@ -86,31 +91,32 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
setRoleList(roleList);
|
||||
setRoleEditUseCase(newRoleEditUseCase);
|
||||
} catch (error) {
|
||||
console.error('获取角色列表失败:', error);
|
||||
console.error("获取角色列表失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, []);
|
||||
|
||||
|
||||
/**
|
||||
* 选择角色
|
||||
* @description 根据角色ID选择角色,并初始化相关的UseCase实例
|
||||
* @param roleId 角色ID
|
||||
*/
|
||||
const selectRole = useCallback(async (role: RoleEntity) => {
|
||||
console.log('selectRole', role);
|
||||
// 根据 role.name 完全替换掉旧的数据
|
||||
setRoleList(prev => prev.map(r => r.name === role.name ? role : r));
|
||||
setSelectedRole(role);
|
||||
// 如果缓存角色为空,则设置缓存角色,名字不同也切换
|
||||
if(!cacheRole||cacheRole.name!==role.name){
|
||||
setCacheRole(role);
|
||||
}
|
||||
const selectRole = useCallback(
|
||||
async (role: RoleEntity) => {
|
||||
console.log("selectRole", role);
|
||||
// 根据 role.name 完全替换掉旧的数据
|
||||
setRoleList((prev) => prev.map((r) => (r.name === role.name ? role : r)));
|
||||
setSelectedRole(role);
|
||||
// 如果缓存角色为空,则设置缓存角色,名字不同也切换
|
||||
if (!cacheRole || cacheRole.name !== role.name) {
|
||||
setCacheRole(role);
|
||||
}
|
||||
|
||||
// 调用selectRole方法
|
||||
roleEditUseCase!.selectRole(role);
|
||||
|
||||
}, [roleEditUseCase]);
|
||||
roleEditUseCase!.selectRole(role);
|
||||
},
|
||||
[roleEditUseCase]
|
||||
);
|
||||
|
||||
/**
|
||||
* 优化AI文本
|
||||
@ -120,36 +126,39 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const optimizeRoleText = useCallback(async () => {
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error('角色编辑UseCase未初始化');
|
||||
throw new Error("角色编辑UseCase未初始化");
|
||||
}
|
||||
|
||||
if (!currentRoleText) {
|
||||
throw new Error('没有可优化的文本内容');
|
||||
throw new Error("没有可优化的文本内容");
|
||||
}
|
||||
|
||||
if (!selectedRole) {
|
||||
throw new Error('没有选中的角色');
|
||||
throw new Error("没有选中的角色");
|
||||
}
|
||||
|
||||
try {
|
||||
const { optimizedDescription, keywords } = await roleEditUseCase.optimizeRoleDescription(selectedRole);
|
||||
const { optimizedDescription, keywords } =
|
||||
await roleEditUseCase.optimizeRoleDescription(selectedRole);
|
||||
setCurrentRoleText(optimizedDescription);
|
||||
// 更新角色列表中的对应角色描述和标签
|
||||
setRoleList(prev =>
|
||||
prev.map(role =>
|
||||
setRoleList((prev) =>
|
||||
prev.map((role) =>
|
||||
role.id === selectedRole?.id
|
||||
? {
|
||||
...role,
|
||||
generateText: optimizedDescription,
|
||||
tags: keywords.map(keyword => ({
|
||||
id: `tag_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
tags: keywords.map((keyword) => ({
|
||||
id: `tag_${Date.now()}_${Math.random()
|
||||
.toString(36)
|
||||
.substr(2, 9)}`,
|
||||
/** 名称 */
|
||||
name: keyword,
|
||||
/** 内容 */
|
||||
content: keyword,
|
||||
loadingProgress: 100,
|
||||
disableEdit: false
|
||||
}))
|
||||
disableEdit: false,
|
||||
})),
|
||||
}
|
||||
: role
|
||||
)
|
||||
@ -157,18 +166,22 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
|
||||
// 更新当前选中角色
|
||||
if (selectedRole) {
|
||||
selectRole({ ...selectedRole, generateText: optimizedDescription, tags: keywords.map(keyword => ({
|
||||
id: `tag_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
/** 名称 */
|
||||
name: keyword,
|
||||
/** 内容 */
|
||||
content: keyword,
|
||||
loadingProgress: 100,
|
||||
disableEdit: false
|
||||
})) });
|
||||
selectRole({
|
||||
...selectedRole,
|
||||
generateText: optimizedDescription,
|
||||
tags: keywords.map((keyword) => ({
|
||||
id: `tag_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
|
||||
/** 名称 */
|
||||
name: keyword,
|
||||
/** 内容 */
|
||||
content: keyword,
|
||||
loadingProgress: 100,
|
||||
disableEdit: false,
|
||||
})),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('优化角色文本失败:', error);
|
||||
console.error("优化角色文本失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, [roleEditUseCase, currentRoleText, selectedRole, selectRole]);
|
||||
@ -180,27 +193,30 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
* @throws {Error} 当没有可编辑的文本或UseCase未初始化时抛出错误
|
||||
* @returns {Promise<void>} 修改完成后的Promise
|
||||
*/
|
||||
const updateRoleText = useCallback(async (newContent: string) => {
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error('角色编辑UseCase未初始化');
|
||||
}
|
||||
const updateRoleText = useCallback(
|
||||
async (newContent: string) => {
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error("角色编辑UseCase未初始化");
|
||||
}
|
||||
|
||||
setCurrentRoleText(newContent);
|
||||
setCurrentRoleText(newContent);
|
||||
|
||||
// 更新角色列表中的对应角色描述
|
||||
setRoleList(prev =>
|
||||
prev.map(role =>
|
||||
role.id === selectedRole?.id
|
||||
? { ...role, generateText: newContent }
|
||||
: role
|
||||
)
|
||||
);
|
||||
// 更新角色列表中的对应角色描述
|
||||
setRoleList((prev) =>
|
||||
prev.map((role) =>
|
||||
role.id === selectedRole?.id
|
||||
? { ...role, generateText: newContent }
|
||||
: role
|
||||
)
|
||||
);
|
||||
|
||||
// 更新当前选中角色
|
||||
if (selectedRole) {
|
||||
selectRole({ ...selectedRole, generateText: newContent });
|
||||
}
|
||||
}, [roleEditUseCase, selectRole, selectedRole]);
|
||||
// 更新当前选中角色
|
||||
if (selectedRole) {
|
||||
selectRole({ ...selectedRole, generateText: newContent });
|
||||
}
|
||||
},
|
||||
[roleEditUseCase, selectRole, selectedRole]
|
||||
);
|
||||
|
||||
/**
|
||||
* 重新生成角色
|
||||
@ -210,15 +226,15 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const regenerateRole = useCallback(async () => {
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error('角色编辑UseCase未初始化');
|
||||
throw new Error("角色编辑UseCase未初始化");
|
||||
}
|
||||
|
||||
if (!selectedRole || !currentRoleText) {
|
||||
throw new Error('缺少重新生成角色所需的数据');
|
||||
throw new Error("缺少重新生成角色所需的数据");
|
||||
}
|
||||
|
||||
if (!projectId) {
|
||||
throw new Error('缺少项目ID,无法重新生成角色');
|
||||
throw new Error("缺少项目ID,无法重新生成角色");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -230,15 +246,13 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
selectRole(newRoleEntity);
|
||||
|
||||
// 更新角色列表
|
||||
setRoleList(prev =>
|
||||
prev.map(role =>
|
||||
role.id === newRoleEntity.id
|
||||
? newRoleEntity
|
||||
: role
|
||||
setRoleList((prev) =>
|
||||
prev.map((role) =>
|
||||
role.id === newRoleEntity.id ? newRoleEntity : role
|
||||
)
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('重新生成角色失败:', error);
|
||||
console.error("重新生成角色失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, [roleEditUseCase, selectedRole, currentRoleText, projectId, selectRole]);
|
||||
@ -263,16 +277,19 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
||||
|
||||
if (!User.id) {
|
||||
throw new Error('无法获取用户ID,请重新登录');
|
||||
throw new Error("无法获取用户ID,请重新登录");
|
||||
}
|
||||
|
||||
// 获取当前选中角色的描述
|
||||
const userDescription = selectedRole?.generateText || '';
|
||||
const userDescription = selectedRole?.generateText || "";
|
||||
|
||||
const roleLibraryList = await useCase!.getRoleLibraryList(User.id, userDescription);
|
||||
const roleLibraryList = await useCase!.getRoleLibraryList(
|
||||
User.id,
|
||||
userDescription
|
||||
);
|
||||
setUserRoleLibrary(roleLibraryList);
|
||||
} catch (error) {
|
||||
console.error('获取用户角色库失败:', error);
|
||||
console.error("获取用户角色库失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, [roleEditUseCase, selectedRole]);
|
||||
@ -284,43 +301,46 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
* @throws {Error} 当未选择角色、API调用失败或UseCase未初始化时抛出错误
|
||||
* @returns {Promise<void>} 替换完成后的Promise
|
||||
*/
|
||||
const replaceRoleWithLibrary = useCallback(async (replaceRoleId: string) => {
|
||||
if (!selectedRole) {
|
||||
throw new Error('请先选择角色');
|
||||
}
|
||||
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error('角色编辑UseCase未初始化');
|
||||
}
|
||||
|
||||
try {
|
||||
await roleEditUseCase.replaceRoleById(selectedRole.id, replaceRoleId);
|
||||
|
||||
// 更新角色列表
|
||||
const libraryRole = userRoleLibrary.find(role => role.id === replaceRoleId);
|
||||
if (libraryRole) {
|
||||
const updatedRole = {
|
||||
...selectedRole,
|
||||
name: libraryRole.name,
|
||||
generateText: libraryRole.generateText,
|
||||
imageUrl: libraryRole.imageUrl,
|
||||
fromDraft: false
|
||||
};
|
||||
|
||||
selectRole(updatedRole);
|
||||
setRoleList(prev =>
|
||||
prev.map(role =>
|
||||
role.id === selectedRole.id
|
||||
? updatedRole
|
||||
: role
|
||||
)
|
||||
);
|
||||
const replaceRoleWithLibrary = useCallback(
|
||||
async (replaceRoleId: string) => {
|
||||
if (!selectedRole) {
|
||||
throw new Error("请先选择角色");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('替换角色失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, [selectedRole, roleEditUseCase, userRoleLibrary, selectRole]);
|
||||
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error("角色编辑UseCase未初始化");
|
||||
}
|
||||
|
||||
try {
|
||||
await roleEditUseCase.replaceRoleById(selectedRole.id, replaceRoleId);
|
||||
|
||||
// 更新角色列表
|
||||
const libraryRole = userRoleLibrary.find(
|
||||
(role) => role.id === replaceRoleId
|
||||
);
|
||||
if (libraryRole) {
|
||||
const updatedRole = {
|
||||
...selectedRole,
|
||||
name: libraryRole.name,
|
||||
generateText: libraryRole.generateText,
|
||||
imageUrl: libraryRole.imageUrl,
|
||||
fromDraft: false,
|
||||
};
|
||||
|
||||
selectRole(updatedRole);
|
||||
setRoleList((prev) =>
|
||||
prev.map((role) =>
|
||||
role.id === selectedRole.id ? updatedRole : role
|
||||
)
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("替换角色失败:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[selectedRole, roleEditUseCase, userRoleLibrary, selectRole]
|
||||
);
|
||||
|
||||
/**
|
||||
* 上传图片并更新角色信息
|
||||
@ -328,62 +348,60 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
* @param file 要上传的文件
|
||||
* @returns {Promise<void>} 上传和分析完成后的Promise
|
||||
*/
|
||||
const uploadImageAndUpdateRole = useCallback(async (file: File) => {
|
||||
if (!selectedRole) {
|
||||
throw new Error('请先选择要更新的角色');
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 上传图片到七牛云
|
||||
const { token } = await getUploadToken();
|
||||
const imageUrl = await uploadToQiniu(file, token);
|
||||
|
||||
// 2. 调用图片分析接口获取描述
|
||||
const result = await analyzeImageDescription({
|
||||
image_url: imageUrl
|
||||
});
|
||||
|
||||
if (!result.successful) {
|
||||
throw new Error(`图片分析失败: ${result.message}`);
|
||||
const uploadImageAndUpdateRole = useCallback(
|
||||
async (file: File) => {
|
||||
if (!selectedRole) {
|
||||
throw new Error("请先选择要更新的角色");
|
||||
}
|
||||
|
||||
const { description, highlights } = result.data;
|
||||
try {
|
||||
// 1. 上传图片到七牛云
|
||||
const { token } = await getUploadToken();
|
||||
const imageUrl = await uploadToQiniu(file, token);
|
||||
|
||||
// 3. 更新当前选中角色的图片、描述和标签
|
||||
const updatedRole = {
|
||||
...selectedRole,
|
||||
imageUrl: imageUrl,
|
||||
generateText: description,
|
||||
tags: highlights.map((highlight: string, index: number) => ({
|
||||
id: `tag_${Date.now()}_${index}`,
|
||||
/** 名称 */
|
||||
name: highlight,
|
||||
/** 内容 */
|
||||
content: highlight,
|
||||
loadingProgress: 100,
|
||||
disableEdit: false
|
||||
}))
|
||||
};
|
||||
// 2. 调用图片分析接口获取描述
|
||||
const result = await analyzeImageDescription({
|
||||
image_url: imageUrl,
|
||||
});
|
||||
|
||||
// 更新选中的角色
|
||||
selectRole(updatedRole);
|
||||
if (!result.successful) {
|
||||
throw new Error(`图片分析失败: ${result.message}`);
|
||||
}
|
||||
|
||||
// 更新角色列表中的对应角色
|
||||
setRoleList(prev =>
|
||||
prev.map(role =>
|
||||
role.id === selectedRole.id
|
||||
? updatedRole
|
||||
: role
|
||||
)
|
||||
);
|
||||
const { description, highlights } = result.data;
|
||||
|
||||
console.log('角色图片和描述更新成功:', updatedRole);
|
||||
// 3. 更新当前选中角色的图片、描述和标签
|
||||
const updatedRole = {
|
||||
...selectedRole,
|
||||
imageUrl: imageUrl,
|
||||
generateText: description,
|
||||
tags: highlights.map((highlight: string, index: number) => ({
|
||||
id: `tag_${Date.now()}_${index}`,
|
||||
/** 名称 */
|
||||
name: highlight,
|
||||
/** 内容 */
|
||||
content: highlight,
|
||||
loadingProgress: 100,
|
||||
disableEdit: false,
|
||||
})),
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('上传图片并分析失败:', error);
|
||||
throw error;
|
||||
}
|
||||
}, [selectedRole, roleEditUseCase, selectRole]);
|
||||
// 更新选中的角色
|
||||
selectRole(updatedRole);
|
||||
|
||||
// 更新角色列表中的对应角色
|
||||
setRoleList((prev) =>
|
||||
prev.map((role) => (role.id === selectedRole.id ? updatedRole : role))
|
||||
);
|
||||
|
||||
console.log("角色图片和描述更新成功:", updatedRole);
|
||||
} catch (error) {
|
||||
console.error("上传图片并分析失败:", error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
[selectedRole, roleEditUseCase, selectRole]
|
||||
);
|
||||
|
||||
/**
|
||||
* 保存重新生成的角色到角色库
|
||||
@ -393,15 +411,15 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const saveRoleToLibrary = useCallback(async () => {
|
||||
if (!selectedRole) {
|
||||
throw new Error('请先选择要保存的角色');
|
||||
throw new Error("请先选择要保存的角色");
|
||||
}
|
||||
|
||||
if (!roleEditUseCase) {
|
||||
throw new Error('角色编辑UseCase未初始化');
|
||||
throw new Error("角色编辑UseCase未初始化");
|
||||
}
|
||||
|
||||
if (!projectId) {
|
||||
throw new Error('缺少项目ID,无法保存角色到角色库');
|
||||
throw new Error("缺少项目ID,无法保存角色到角色库");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -409,7 +427,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
|
||||
|
||||
if (!User.id) {
|
||||
throw new Error('无法获取用户ID,请重新登录');
|
||||
throw new Error("无法获取用户ID,请重新登录");
|
||||
}
|
||||
|
||||
// 调用保存重新生成角色到角色库的方法
|
||||
@ -418,11 +436,22 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
projectId,
|
||||
String(User.id)
|
||||
);
|
||||
selectRole({
|
||||
...selectedRole,
|
||||
id: result.character_id,
|
||||
fromDraft: true,
|
||||
});
|
||||
|
||||
console.log('角色保存到角色库成功:', result);
|
||||
|
||||
SaveEditUseCase.setCharacterId([
|
||||
...SaveEditUseCase.characterId,
|
||||
{
|
||||
character_id: result.character_id,
|
||||
name: selectedRole.name,
|
||||
},
|
||||
]);
|
||||
console.log("角色保存到角色库成功:", result);
|
||||
} catch (error) {
|
||||
console.error('保存角色到角色库失败:', error);
|
||||
console.error("保存角色到角色库失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, [selectedRole, roleEditUseCase, projectId]);
|
||||
@ -435,21 +464,21 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
*/
|
||||
const saveData = useCallback(async () => {
|
||||
if (!projectId) {
|
||||
throw new Error('缺少项目ID,无法保存数据');
|
||||
throw new Error("缺少项目ID,无法保存数据");
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await checkShotVideoStatus({
|
||||
project_id: projectId
|
||||
project_id: projectId,
|
||||
});
|
||||
|
||||
if (!result.successful) {
|
||||
throw new Error(`保存数据失败: ${result.message}`);
|
||||
}
|
||||
|
||||
console.log('数据保存成功');
|
||||
console.log("数据保存成功");
|
||||
} catch (error) {
|
||||
console.error('保存数据失败:', error);
|
||||
console.error("保存数据失败:", error);
|
||||
throw error;
|
||||
}
|
||||
}, [projectId]);
|
||||
@ -472,6 +501,6 @@ export const useRoleServiceHook = (): UseRoleService => {
|
||||
replaceRoleWithLibrary,
|
||||
uploadImageAndUpdateRole,
|
||||
saveRoleToLibrary,
|
||||
saveData
|
||||
saveData,
|
||||
};
|
||||
};
|
||||
|
||||
@ -9,6 +9,7 @@ import {
|
||||
import { VideoSegmentEntity } from "../domain/Entities";
|
||||
import { LensType, SimpleCharacter } from "../domain/valueObject";
|
||||
import { getUploadToken, uploadToQiniu } from "@/api/common";
|
||||
import { SaveEditUseCase } from "../usecase/SaveEditUseCase";
|
||||
|
||||
/**
|
||||
* 视频片段服务Hook接口
|
||||
@ -181,7 +182,13 @@ export const useShotService = (): UseShotService => {
|
||||
|
||||
// 保存任务ID用于后续状态查询
|
||||
setGenerateTaskIds(prev => prev.add(taskResult.task_id));
|
||||
|
||||
SaveEditUseCase.setVideoTasks([
|
||||
...SaveEditUseCase.videoTasks,
|
||||
{
|
||||
task_id: taskResult.task_id,
|
||||
video_ids: [selectedSegment!.id],
|
||||
},
|
||||
]);
|
||||
// 如果重新生成的是现有片段,更新其状态为处理中 (0: 视频加载中)
|
||||
if (selectedSegment) {
|
||||
setVideoSegments((prev) =>
|
||||
|
||||
190
app/service/usecase/SaveEditUseCase.ts
Normal file
190
app/service/usecase/SaveEditUseCase.ts
Normal file
@ -0,0 +1,190 @@
|
||||
import { modifyCharacterOrScene } from '@/api/video_flow';
|
||||
|
||||
/**
|
||||
* 保存编辑用例类
|
||||
* @description 保存接口所需的参数数据,提供保存和清空方法
|
||||
*/
|
||||
export class SaveEditUseCase {
|
||||
static projectId: string = '';
|
||||
static characterId: {
|
||||
/** 角色ID */
|
||||
character_id: string;
|
||||
/** 角色名称 */
|
||||
name: string;
|
||||
}[] = [];
|
||||
static videoTasks: Array<{
|
||||
task_id: string;
|
||||
video_ids: string[];
|
||||
}> = [];
|
||||
|
||||
/**
|
||||
* 设置项目ID
|
||||
* @param projectId 项目ID
|
||||
*/
|
||||
static setProjectId(projectId: string): void {
|
||||
SaveEditUseCase.projectId = projectId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置角色ID
|
||||
* @param characterId 角色ID
|
||||
*/
|
||||
static setCharacterId(characterId: {
|
||||
/** 角色ID */
|
||||
character_id: string;
|
||||
/** 角色名称 */
|
||||
name: string;
|
||||
}[]): void {
|
||||
// 使用Set根据character_id去重
|
||||
const seenIds = new Set<string>();
|
||||
SaveEditUseCase.characterId = characterId.filter(character => {
|
||||
if (seenIds.has(character.character_id)) {
|
||||
return false;
|
||||
}
|
||||
seenIds.add(character.character_id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置视频任务列表
|
||||
* @param videoTasks 视频任务列表
|
||||
*/
|
||||
static setVideoTasks(videoTasks: Array<{
|
||||
task_id: string;
|
||||
video_ids: string[];
|
||||
}>): void {
|
||||
// 使用Set根据task_id去重
|
||||
const seenIds = new Set<string>();
|
||||
SaveEditUseCase.videoTasks = videoTasks.filter(task => {
|
||||
if (seenIds.has(task.task_id)) {
|
||||
return false;
|
||||
}
|
||||
seenIds.add(task.task_id);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加视频任务
|
||||
* @param taskId 任务ID
|
||||
* @param videoIds 视频ID列表
|
||||
*/
|
||||
static addVideoTask(taskId: string, videoIds: string[]): void {
|
||||
SaveEditUseCase.videoTasks.push({
|
||||
task_id: taskId,
|
||||
video_ids: videoIds,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 主要保存方法
|
||||
* @description 调用保存接口,传入当前类内保存的数据
|
||||
* @returns Promise<保存结果>
|
||||
*/
|
||||
static async saveData(): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: any;
|
||||
}> {
|
||||
try {
|
||||
if (!SaveEditUseCase.projectId) {
|
||||
throw new Error('项目ID不能为空');
|
||||
}
|
||||
|
||||
if (SaveEditUseCase.videoTasks.length === 0) {
|
||||
throw new Error('视频任务列表不能为空');
|
||||
}
|
||||
|
||||
const response = await modifyCharacterOrScene({
|
||||
project_id: SaveEditUseCase.projectId,
|
||||
character_id: SaveEditUseCase.characterId,
|
||||
video_tasks: SaveEditUseCase.videoTasks,
|
||||
});
|
||||
|
||||
if (!response.successful) {
|
||||
throw new Error(response.message || '保存数据失败');
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: '数据保存成功',
|
||||
data: response.data,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('保存数据失败:', error);
|
||||
return {
|
||||
success: false,
|
||||
message: error instanceof Error ? error.message : '保存数据失败',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存角色数据方法
|
||||
* @description 保存character_id数据
|
||||
* @returns Promise<保存结果>
|
||||
*/
|
||||
static async saveRoleData(): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: any;
|
||||
}> {
|
||||
// 角色数据保存就是保存character_id
|
||||
return SaveEditUseCase.saveData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存镜头数据方法
|
||||
* @description 保存video_tasks数据
|
||||
* @returns Promise<保存结果>
|
||||
*/
|
||||
static async saveShotData(): Promise<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
data?: any;
|
||||
}> {
|
||||
// 镜头数据保存就是保存video_tasks
|
||||
return SaveEditUseCase.saveData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空数据方法
|
||||
* @description 清空当前类内保存的所有数据
|
||||
*/
|
||||
static clearData(): void {
|
||||
SaveEditUseCase.projectId = '';
|
||||
SaveEditUseCase.characterId = [];
|
||||
SaveEditUseCase.videoTasks = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前保存的数据
|
||||
* @returns 当前保存的数据对象
|
||||
*/
|
||||
static getCurrentData(): {
|
||||
projectId: string;
|
||||
characterId: {
|
||||
character_id: string;
|
||||
name: string;
|
||||
}[];
|
||||
videoTasks: Array<{
|
||||
task_id: string;
|
||||
video_ids: string[];
|
||||
}>;
|
||||
} {
|
||||
return {
|
||||
projectId: SaveEditUseCase.projectId,
|
||||
characterId: [...SaveEditUseCase.characterId],
|
||||
videoTasks: [...SaveEditUseCase.videoTasks],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建保存编辑用例实例
|
||||
* @returns {SaveEditUseCase} 保存编辑用例实例
|
||||
*/
|
||||
export const createSaveEditUseCase = (): SaveEditUseCase => {
|
||||
return new SaveEditUseCase();
|
||||
};
|
||||
@ -13,6 +13,8 @@ import { usePlaybackControls } from "./work-flow/use-playback-controls";
|
||||
import { AlertCircle, RefreshCw, Pause, Play, ChevronLast } from "lucide-react";
|
||||
import { motion } from "framer-motion";
|
||||
import { GlassIconButton } from '@/components/ui/glass-icon-button';
|
||||
import { SaveEditUseCase } from "@/app/service/usecase/SaveEditUseCase";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
export default function WorkFlow() {
|
||||
console.log('WorkFlow--0294877777777777')
|
||||
@ -20,6 +22,10 @@ export default function WorkFlow() {
|
||||
const [isEditModalOpen, setIsEditModalOpen] = React.useState(false);
|
||||
const [activeEditTab, setActiveEditTab] = React.useState('1');
|
||||
|
||||
const searchParams = useSearchParams();
|
||||
const episodeId = searchParams.get('episodeId') || '';
|
||||
|
||||
SaveEditUseCase.setProjectId(episodeId);
|
||||
// 使用自定义 hooks 管理状态
|
||||
const {
|
||||
taskObject,
|
||||
@ -64,7 +70,7 @@ export default function WorkFlow() {
|
||||
|
||||
// 跟踪是否已经自动开始播放过,避免重复触发
|
||||
const hasAutoStartedRef = useRef(false);
|
||||
|
||||
|
||||
// 跟踪循环播放的起始索引,用于判断是否完成一轮循环
|
||||
const loopStartIndexRef = useRef<number | null>(null);
|
||||
|
||||
@ -136,13 +142,13 @@ export default function WorkFlow() {
|
||||
</div>
|
||||
</div>
|
||||
<div className="media-Ocdu1O rounded-lg">
|
||||
<div
|
||||
className="videoContainer-qteKNi"
|
||||
style={(currentStep !== '6' && currentStep !== '0') ? { flex: 3 } : {}}
|
||||
<div
|
||||
className="videoContainer-qteKNi"
|
||||
style={(currentStep !== '6' && currentStep !== '0') ? { flex: 3 } : {}}
|
||||
ref={containerRef}
|
||||
>
|
||||
{dataLoadError ? (
|
||||
<motion.div
|
||||
<motion.div
|
||||
className="flex flex-col items-center justify-center w-full aspect-video rounded-lg bg-red-50 border-2 border-red-200"
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
@ -157,11 +163,11 @@ export default function WorkFlow() {
|
||||
<AlertCircle className="w-8 h-8 text-red-500" />
|
||||
<h3 className="text-lg font-medium text-red-800">数据加载失败</h3>
|
||||
</motion.div>
|
||||
|
||||
|
||||
<p className="text-red-600 text-center mb-6 max-w-md px-4">
|
||||
{dataLoadError}
|
||||
</p>
|
||||
|
||||
|
||||
<motion.button
|
||||
className="flex items-center gap-2 px-6 py-3 bg-red-500 text-white rounded-lg hover:bg-red-600 transition-colors"
|
||||
onClick={() => retryLoadData?.()}
|
||||
@ -245,7 +251,7 @@ export default function WorkFlow() {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
{/* AI 建议栏 */}
|
||||
<ErrorBoundary>
|
||||
@ -262,7 +268,10 @@ export default function WorkFlow() {
|
||||
<EditModal
|
||||
isOpen={isEditModalOpen}
|
||||
activeEditTab={activeEditTab}
|
||||
onClose={() => setIsEditModalOpen(false)}
|
||||
onClose={() => {
|
||||
SaveEditUseCase.clearData();
|
||||
setIsEditModalOpen(false)
|
||||
}}
|
||||
taskStatus={taskObject?.taskStatus || '1'}
|
||||
taskSketch={taskSketch}
|
||||
sketchVideo={taskVideos}
|
||||
@ -280,4 +289,4 @@ export default function WorkFlow() {
|
||||
</div>
|
||||
</ErrorBoundary>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,7 +109,6 @@ const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null
|
||||
if (disabled) return;
|
||||
// 切换前 检查是否更新
|
||||
const isUpdate = checkUpdate(activeTab);
|
||||
console.log('contentEditableRef---isUpdate', isUpdate);
|
||||
if (isUpdate) {
|
||||
setPendingSwitchTabId(tabId); // 记录要切换到的目标tab
|
||||
setRemindFallbackText('You must click Apply button to save the current changes.');
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user