forked from 77media/video-flow
更新角色和场景服务Hook,新增获取角色列表、角色数据、场景列表和场景数据的API接口;实现角色替换功能;优化相关状态管理和数据初始化逻辑;删除不再使用的RoleService.puml文件。
This commit is contained in:
parent
70b6ce5d4c
commit
f9e05b3a23
@ -322,6 +322,64 @@ export const getRoleShots = async (request: {
|
|||||||
return post<ApiResponse<any>>('/movie/get_role_shots', request);
|
return post<ApiResponse<any>>('/movie/get_role_shots', request);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取角色列表
|
||||||
|
* @param request - 获取角色列表请求参数
|
||||||
|
* @returns Promise<ApiResponse<角色实体列表>>
|
||||||
|
*/
|
||||||
|
export const getRoleList = async (request: {
|
||||||
|
/** 项目ID */
|
||||||
|
projectId: string;
|
||||||
|
}): Promise<ApiResponse<RoleEntity[]>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/get_role_list', request);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取角色数据
|
||||||
|
* @param request - 获取角色数据请求参数
|
||||||
|
* @returns Promise<ApiResponse<{ AI文本数据, 标签列表 }>>
|
||||||
|
*/
|
||||||
|
export const getRoleData = async (request: {
|
||||||
|
/** 角色ID */
|
||||||
|
roleId: string;
|
||||||
|
}): Promise<ApiResponse<{
|
||||||
|
/** AI文本数据 */
|
||||||
|
text: AITextEntity;
|
||||||
|
/** 标签列表 */
|
||||||
|
tags: TagEntity[];
|
||||||
|
}>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/get_role_data', request);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取场景数据
|
||||||
|
* @param request - 获取场景数据请求参数
|
||||||
|
* @returns Promise<ApiResponse<{ AI文本数据, 标签列表 }>>
|
||||||
|
*/
|
||||||
|
export const getSceneData = async (request: {
|
||||||
|
/** 场景ID */
|
||||||
|
sceneId: string;
|
||||||
|
}): Promise<ApiResponse<{
|
||||||
|
/** AI文本数据 */
|
||||||
|
text: AITextEntity;
|
||||||
|
/** 标签列表 */
|
||||||
|
tags: TagEntity[];
|
||||||
|
}>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/get_scene_data', request);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取场景列表
|
||||||
|
* @param request - 获取场景列表请求参数
|
||||||
|
* @returns Promise<ApiResponse<场景实体列表>>
|
||||||
|
*/
|
||||||
|
export const getSceneList = async (request: {
|
||||||
|
/** 项目ID */
|
||||||
|
projectId: string;
|
||||||
|
}): Promise<ApiResponse<SceneEntity[]>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/get_scene_list', request);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取场景应用到的分镜列表
|
* 获取场景应用到的分镜列表
|
||||||
* @param request - 获取场景分镜列表请求参数
|
* @param request - 获取场景分镜列表请求参数
|
||||||
@ -339,3 +397,25 @@ export const getSceneShots = async (request: {
|
|||||||
return post<ApiResponse<any>>('/movie/get_scene_shots', request);
|
return post<ApiResponse<any>>('/movie/get_scene_shots', request);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户角色库
|
||||||
|
* @returns Promise<ApiResponse<角色实体列表>>
|
||||||
|
*/
|
||||||
|
export const getUserRoleLibrary = async (): Promise<ApiResponse<RoleEntity[]>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/get_user_role_library', {});
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换角色
|
||||||
|
* @param request - 替换角色请求参数
|
||||||
|
* @returns Promise<ApiResponse<替换结果>>
|
||||||
|
*/
|
||||||
|
export const replaceRole = async (request: {
|
||||||
|
/** 当前角色ID */
|
||||||
|
currentRoleId: string;
|
||||||
|
/** 替换的角色ID */
|
||||||
|
replaceRoleId: string;
|
||||||
|
}): Promise<ApiResponse<any>> => {
|
||||||
|
return post<ApiResponse<any>>('/movie/replace_role', request);
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,151 +0,0 @@
|
|||||||
@startuml RoleService Hook 架构图
|
|
||||||
|
|
||||||
!theme plain
|
|
||||||
skinparam backgroundColor #FFFFFF
|
|
||||||
skinparam componentStyle rectangle
|
|
||||||
|
|
||||||
' 主要模块
|
|
||||||
package "RoleService Hook" as RoleServiceHook {
|
|
||||||
component "响应式状态管理" as StateManagement
|
|
||||||
component "计算属性" as ComputedProps
|
|
||||||
component "角色操作方法" as RoleOperations
|
|
||||||
component "文本操作方法" as TextOperations
|
|
||||||
component "标签操作方法" as TagOperations
|
|
||||||
component "分镜操作方法" as ShotOperations
|
|
||||||
}
|
|
||||||
|
|
||||||
' API层
|
|
||||||
package "API接口层" as APILayer {
|
|
||||||
component "角色相关API" as RoleAPI {
|
|
||||||
[regenerateRole()]
|
|
||||||
[applyRoleToShots()]
|
|
||||||
[getRoleShots()]
|
|
||||||
}
|
|
||||||
|
|
||||||
component "文本相关API" as TextAPI {
|
|
||||||
[updateText()]
|
|
||||||
}
|
|
||||||
|
|
||||||
component "标签相关API" as TagAPI {
|
|
||||||
[updateTag()]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
' UseCase层
|
|
||||||
package "UseCase层" as UseCaseLayer {
|
|
||||||
component "RoleEditUseCase" as RoleEditUseCase {
|
|
||||||
[AIgenerateRole(prompt, tags)]
|
|
||||||
[applyRole(shotIds)]
|
|
||||||
}
|
|
||||||
|
|
||||||
component "TextEditUseCase" as TextEditUseCase {
|
|
||||||
[updateText(content)]
|
|
||||||
[getOptimizedContent()]
|
|
||||||
}
|
|
||||||
|
|
||||||
component "TagEditUseCase" as TagEditUseCase {
|
|
||||||
[updateTag(content)]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
' Domain层
|
|
||||||
package "Domain层" as DomainLayer {
|
|
||||||
component "实体定义" as Entities {
|
|
||||||
[RoleEntity]
|
|
||||||
[AITextEntity]
|
|
||||||
[TagEntity]
|
|
||||||
[ShotEntity]
|
|
||||||
}
|
|
||||||
|
|
||||||
component "可编辑项" as Items {
|
|
||||||
[RoleItem]
|
|
||||||
[TextItem]
|
|
||||||
[TagItem]
|
|
||||||
[ShotItem]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
' React Hook
|
|
||||||
package "React Hook" as ReactHook {
|
|
||||||
component "useState" as UseState
|
|
||||||
component "useCallback" as UseCallback
|
|
||||||
component "useMemo" as UseMemo
|
|
||||||
}
|
|
||||||
|
|
||||||
' 依赖关系
|
|
||||||
' Hook内部依赖
|
|
||||||
RoleServiceHook --> StateManagement : 管理状态
|
|
||||||
RoleServiceHook --> ComputedProps : 计算属性
|
|
||||||
RoleServiceHook --> RoleOperations : 角色操作
|
|
||||||
RoleServiceHook --> TextOperations : 文本操作
|
|
||||||
RoleServiceHook --> TagOperations : 标签操作
|
|
||||||
RoleServiceHook --> ShotOperations : 分镜操作
|
|
||||||
|
|
||||||
' 操作方法依赖UseCase
|
|
||||||
RoleOperations --> RoleEditUseCase : 调用
|
|
||||||
TextOperations --> TextEditUseCase : 调用
|
|
||||||
TagOperations --> TagEditUseCase : 调用
|
|
||||||
ShotOperations --> RoleEditUseCase : 调用
|
|
||||||
|
|
||||||
' UseCase依赖API
|
|
||||||
RoleEditUseCase --> RoleAPI : 调用
|
|
||||||
TextEditUseCase --> TextAPI : 调用
|
|
||||||
TagEditUseCase --> TagAPI : 调用
|
|
||||||
|
|
||||||
' 状态管理依赖Domain
|
|
||||||
StateManagement --> Items : 使用
|
|
||||||
ComputedProps --> Entities : 计算
|
|
||||||
RoleOperations --> Items : 操作
|
|
||||||
TextOperations --> Items : 操作
|
|
||||||
TagOperations --> Items : 操作
|
|
||||||
ShotOperations --> Items : 操作
|
|
||||||
|
|
||||||
' React Hook依赖
|
|
||||||
RoleServiceHook --> UseState : 状态管理
|
|
||||||
RoleServiceHook --> UseCallback : 方法优化
|
|
||||||
RoleServiceHook --> UseMemo : 计算优化
|
|
||||||
|
|
||||||
' 数据流
|
|
||||||
note right of StateManagement
|
|
||||||
响应式状态:
|
|
||||||
- roleList: 角色列表
|
|
||||||
- selectedRole: 当前选中角色
|
|
||||||
- currentRoleText: 当前AI文本
|
|
||||||
- currentRoleTags: 当前标签列表
|
|
||||||
- shotSelectionList: 分镜选择列表
|
|
||||||
end note
|
|
||||||
|
|
||||||
note right of ComputedProps
|
|
||||||
计算属性:
|
|
||||||
- roleImageUrl: 角色图片URL
|
|
||||||
- isAllShotsSelected: 是否全选
|
|
||||||
- selectedShotsCount: 选中数量
|
|
||||||
end note
|
|
||||||
|
|
||||||
note right of RoleOperations
|
|
||||||
角色操作:
|
|
||||||
- selectRole: 选择角色
|
|
||||||
- regenerateRole: 重新生成
|
|
||||||
end note
|
|
||||||
|
|
||||||
note right of TextOperations
|
|
||||||
文本操作:
|
|
||||||
- optimizeRoleText: 优化文本
|
|
||||||
- updateRoleText: 修改文本
|
|
||||||
end note
|
|
||||||
|
|
||||||
note right of TagOperations
|
|
||||||
标签操作:
|
|
||||||
- updateTagContent: 修改标签
|
|
||||||
end note
|
|
||||||
|
|
||||||
note right of ShotOperations
|
|
||||||
分镜操作:
|
|
||||||
- fetchRoleShots: 获取分镜列表
|
|
||||||
- selectAllShots: 全选
|
|
||||||
- invertShotSelection: 反选
|
|
||||||
- toggleShotSelection: 切换选择
|
|
||||||
- applyRoleToSelectedShots: 应用角色
|
|
||||||
end note
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
@ -4,7 +4,7 @@ import { RoleItem, TagItem, TextItem, ShotItem } from '../domain/Item';
|
|||||||
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
|
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
|
||||||
import { TagEditUseCase } from '../usecase/TagEditUseCase';
|
import { TagEditUseCase } from '../usecase/TagEditUseCase';
|
||||||
import { TextEditUseCase } from '../usecase/TextEditUseCase';
|
import { TextEditUseCase } from '../usecase/TextEditUseCase';
|
||||||
import { getRoleShots } from '@/api/video_flow';
|
import { getRoleShots, getRoleData, getRoleList, getUserRoleLibrary, replaceRole } from '@/api/video_flow';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分镜选择项接口
|
* 分镜选择项接口
|
||||||
@ -43,12 +43,15 @@ interface UseRoleService {
|
|||||||
isAllShotsSelected: boolean;
|
isAllShotsSelected: boolean;
|
||||||
/** 已选中的分镜数量 */
|
/** 已选中的分镜数量 */
|
||||||
selectedShotsCount: number;
|
selectedShotsCount: number;
|
||||||
|
/** 用户角色库 */
|
||||||
|
userRoleLibrary: RoleItem[];
|
||||||
// 操作方法
|
// 操作方法
|
||||||
|
/** 获取角色列表 */
|
||||||
|
fetchRoleList: (projectId: string) => Promise<void>;
|
||||||
/** 选择角色 */
|
/** 选择角色 */
|
||||||
selectRole: (roleId: string) => void;
|
selectRole: (roleId: string) => void;
|
||||||
/** 设置当前角色的AI文本和标签 */
|
/** 初始化当前选中角色的AI文本和标签数据 */
|
||||||
setCurrentRoleData: (text: TextItem, tags: TagItem[]) => void;
|
initializeRoleData: () => Promise<void>;
|
||||||
/** 优化AI文本 */
|
/** 优化AI文本 */
|
||||||
optimizeRoleText: () => Promise<void>;
|
optimizeRoleText: () => Promise<void>;
|
||||||
/** 修改AI文本 */
|
/** 修改AI文本 */
|
||||||
@ -65,6 +68,11 @@ interface UseRoleService {
|
|||||||
toggleShotSelection: (shotId: string) => void;
|
toggleShotSelection: (shotId: string) => void;
|
||||||
/** 应用角色到选中的分镜 */
|
/** 应用角色到选中的分镜 */
|
||||||
applyRoleToSelectedShots: () => Promise<void>;
|
applyRoleToSelectedShots: () => Promise<void>;
|
||||||
|
/** 获取用户角色库 */
|
||||||
|
fetchUserRoleLibrary: () => Promise<void>;
|
||||||
|
/** 替换角色 */
|
||||||
|
replaceRoleWithLibrary: (replaceRoleId: string) => Promise<void>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -78,6 +86,7 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
const [currentRoleText, setCurrentRoleText] = useState<TextItem | null>(null);
|
const [currentRoleText, setCurrentRoleText] = useState<TextItem | null>(null);
|
||||||
const [currentRoleTags, setCurrentRoleTags] = useState<TagItem[]>([]);
|
const [currentRoleTags, setCurrentRoleTags] = useState<TagItem[]>([]);
|
||||||
const [shotSelectionList, setShotSelectionList] = useState<ShotSelectionItem[]>([]);
|
const [shotSelectionList, setShotSelectionList] = useState<ShotSelectionItem[]>([]);
|
||||||
|
const [userRoleLibrary, setUserRoleLibrary] = useState<RoleItem[]>([]);
|
||||||
|
|
||||||
// UseCase实例 - 在角色选择时初始化
|
// UseCase实例 - 在角色选择时初始化
|
||||||
const [roleEditUseCase, setRoleEditUseCase] = useState<RoleEditUseCase | null>(null);
|
const [roleEditUseCase, setRoleEditUseCase] = useState<RoleEditUseCase | null>(null);
|
||||||
@ -109,26 +118,98 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
return shotSelectionList.filter(shot => shot.selected).length;
|
return shotSelectionList.filter(shot => shot.selected).length;
|
||||||
}, [shotSelectionList]);
|
}, [shotSelectionList]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取角色列表
|
||||||
|
* @description 根据项目ID获取所有角色列表
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @throws {Error} 当API调用失败时抛出错误
|
||||||
|
* @returns {Promise<void>} 获取完成后的Promise
|
||||||
|
*/
|
||||||
|
const fetchRoleList = useCallback(async (projectId: string) => {
|
||||||
|
try {
|
||||||
|
const response = await getRoleList({
|
||||||
|
projectId: projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.successful) {
|
||||||
|
const roleItems = response.data.map(role => new RoleItem(role));
|
||||||
|
setRoleList(roleItems);
|
||||||
|
} else {
|
||||||
|
throw new Error(`获取角色列表失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取角色列表失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 选择角色
|
* 选择角色
|
||||||
* @description 根据角色ID选择角色,并初始化相关的UseCase实例
|
* @description 根据角色ID选择角色,并初始化相关的UseCase实例
|
||||||
* @param roleId 角色ID
|
* @param roleId 角色ID
|
||||||
*/
|
*/
|
||||||
const selectRole = useCallback((roleId: string) => {
|
const selectRole = useCallback(async (roleId: string) => {
|
||||||
const role = roleList.find(r => r.entity.id === roleId);
|
const role = roleList.find(r => r.entity.id === roleId);
|
||||||
if (role) {
|
if (role) {
|
||||||
setSelectedRole(role);
|
setSelectedRole(role);
|
||||||
|
|
||||||
// 初始化UseCase实例
|
// 初始化角色编辑UseCase实例
|
||||||
setRoleEditUseCase(new RoleEditUseCase(role));
|
setRoleEditUseCase(new RoleEditUseCase(role));
|
||||||
setTextEditUseCase(null); // 文本UseCase在获取到文本后初始化
|
|
||||||
setTagEditUseCases(new Map()); // 标签UseCase在获取到标签后初始化
|
|
||||||
|
|
||||||
|
// 清空文本和标签相关状态
|
||||||
|
setTextEditUseCase(null);
|
||||||
|
setTagEditUseCases(new Map());
|
||||||
setCurrentRoleText(null);
|
setCurrentRoleText(null);
|
||||||
setCurrentRoleTags([]);
|
setCurrentRoleTags([]);
|
||||||
|
await initializeRoleData();
|
||||||
}
|
}
|
||||||
}, [roleList]);
|
}, [roleList]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化角色数据
|
||||||
|
* @description 初始化当前选中角色的AI文本和标签数据
|
||||||
|
* @throws {Error} 当未选择角色或API调用失败时抛出错误
|
||||||
|
* @returns {Promise<void>} 初始化完成后的Promise
|
||||||
|
*/
|
||||||
|
const initializeRoleData = useCallback(async () => {
|
||||||
|
if (!selectedRole) {
|
||||||
|
throw new Error('请先选择角色');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await getRoleData({
|
||||||
|
roleId: selectedRole.entity.id
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.successful) {
|
||||||
|
const { text, tags } = response.data;
|
||||||
|
const textItem = new TextItem(text);
|
||||||
|
const tagItems = tags.map(tag => new TagItem(tag));
|
||||||
|
|
||||||
|
// 设置当前角色的AI文本和标签
|
||||||
|
setCurrentRoleText(textItem);
|
||||||
|
setCurrentRoleTags(tagItems);
|
||||||
|
|
||||||
|
// 初始化文本UseCase
|
||||||
|
setTextEditUseCase(new TextEditUseCase(textItem));
|
||||||
|
|
||||||
|
// 初始化标签UseCase
|
||||||
|
const newTagEditUseCases = new Map<string, TagEditUseCase>();
|
||||||
|
tagItems.forEach(tag => {
|
||||||
|
newTagEditUseCases.set(tag.entity.id, new TagEditUseCase(tag));
|
||||||
|
});
|
||||||
|
setTagEditUseCases(newTagEditUseCases);
|
||||||
|
} else {
|
||||||
|
throw new Error(`获取角色数据失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化角色数据失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, [selectedRole]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 优化AI文本
|
* 优化AI文本
|
||||||
* @description 对当前角色的AI文本进行优化,无文本时不可进行优化
|
* @description 对当前角色的AI文本进行优化,无文本时不可进行优化
|
||||||
@ -325,27 +406,62 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
}, [roleEditUseCase, selectedRole, shotSelectionList]);
|
}, [roleEditUseCase, selectedRole, shotSelectionList]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置当前角色的AI文本和标签
|
* 获取用户角色库
|
||||||
* @description 设置当前角色的AI文本和标签,并初始化对应的UseCase
|
* @description 获取当前用户的角色库列表
|
||||||
* @param text AI文本项
|
* @throws {Error} 当API调用失败时抛出错误
|
||||||
* @param tags 标签项列表
|
* @returns {Promise<void>} 获取完成后的Promise
|
||||||
*/
|
*/
|
||||||
const setCurrentRoleData = useCallback((text: TextItem, tags: TagItem[]) => {
|
const fetchUserRoleLibrary = useCallback(async () => {
|
||||||
setCurrentRoleText(text);
|
try {
|
||||||
setCurrentRoleTags(tags);
|
const response = await getUserRoleLibrary();
|
||||||
|
|
||||||
// 初始化文本UseCase
|
if (response.successful) {
|
||||||
if (text) {
|
const roleItems = response.data.map(role => new RoleItem(role));
|
||||||
setTextEditUseCase(new TextEditUseCase(text));
|
setUserRoleLibrary(roleItems);
|
||||||
|
} else {
|
||||||
|
throw new Error(`获取用户角色库失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取用户角色库失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 替换角色
|
||||||
|
* @description 使用角色库中的角色替换当前角色,并重新获取角色详细数据
|
||||||
|
* @param replaceRoleId 替换的角色ID
|
||||||
|
* @throws {Error} 当未选择角色、API调用失败或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 替换完成后的Promise
|
||||||
|
*/
|
||||||
|
const replaceRoleWithLibrary = useCallback(async (replaceRoleId: string) => {
|
||||||
|
if (!selectedRole) {
|
||||||
|
throw new Error('请先选择角色');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化标签UseCase
|
if (!roleEditUseCase) {
|
||||||
const newTagEditUseCases = new Map<string, TagEditUseCase>();
|
throw new Error('角色编辑UseCase未初始化');
|
||||||
tags.forEach(tag => {
|
}
|
||||||
newTagEditUseCases.set(tag.entity.id, new TagEditUseCase(tag));
|
|
||||||
});
|
try {
|
||||||
setTagEditUseCases(newTagEditUseCases);
|
const response = await replaceRole({
|
||||||
}, []);
|
currentRoleId: selectedRole.entity.id,
|
||||||
|
replaceRoleId: replaceRoleId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.successful) {
|
||||||
|
// 重新获取当前角色的详细数据
|
||||||
|
await initializeRoleData();
|
||||||
|
} else {
|
||||||
|
throw new Error(`替换角色失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('替换角色失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, [selectedRole, roleEditUseCase, initializeRoleData]);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// 响应式数据
|
// 响应式数据
|
||||||
@ -365,12 +481,15 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
isAllShotsSelected,
|
isAllShotsSelected,
|
||||||
/** 已选中的分镜数量 */
|
/** 已选中的分镜数量 */
|
||||||
selectedShotsCount,
|
selectedShotsCount,
|
||||||
|
/** 用户角色库 */
|
||||||
|
userRoleLibrary,
|
||||||
// 操作方法
|
// 操作方法
|
||||||
|
/** 获取角色列表 */
|
||||||
|
fetchRoleList,
|
||||||
/** 选择角色 */
|
/** 选择角色 */
|
||||||
selectRole,
|
selectRole,
|
||||||
/** 设置当前角色的AI文本和标签 */
|
/** 初始化当前选中角色的AI文本和标签数据 */
|
||||||
setCurrentRoleData,
|
initializeRoleData,
|
||||||
/** 优化AI文本 */
|
/** 优化AI文本 */
|
||||||
optimizeRoleText,
|
optimizeRoleText,
|
||||||
/** 修改AI文本 */
|
/** 修改AI文本 */
|
||||||
@ -386,6 +505,11 @@ export const useRoleServiceHook = (): UseRoleService => {
|
|||||||
/** 选择/取消选择单个分镜 */
|
/** 选择/取消选择单个分镜 */
|
||||||
toggleShotSelection,
|
toggleShotSelection,
|
||||||
/** 应用角色到选中的分镜 */
|
/** 应用角色到选中的分镜 */
|
||||||
applyRoleToSelectedShots
|
applyRoleToSelectedShots,
|
||||||
|
/** 获取用户角色库 */
|
||||||
|
fetchUserRoleLibrary,
|
||||||
|
/** 替换角色 */
|
||||||
|
replaceRoleWithLibrary,
|
||||||
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { SceneItem, TagItem, TextItem, ShotItem } from '../domain/Item';
|
|||||||
import { SceneEditUseCase } from '../usecase/SceneEditUseCase';
|
import { SceneEditUseCase } from '../usecase/SceneEditUseCase';
|
||||||
import { TagEditUseCase } from '../usecase/TagEditUseCase';
|
import { TagEditUseCase } from '../usecase/TagEditUseCase';
|
||||||
import { TextEditUseCase } from '../usecase/TextEditUseCase';
|
import { TextEditUseCase } from '../usecase/TextEditUseCase';
|
||||||
import { getSceneShots } from '@/api/video_flow';
|
import { getSceneShots, getSceneData, getSceneList } from '@/api/video_flow';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分镜选择项接口
|
* 分镜选择项接口
|
||||||
@ -45,10 +45,12 @@ interface UseSceneService {
|
|||||||
selectedShotsCount: number;
|
selectedShotsCount: number;
|
||||||
|
|
||||||
// 操作方法
|
// 操作方法
|
||||||
|
/** 获取场景列表 */
|
||||||
|
fetchSceneList: (projectId: string) => Promise<void>;
|
||||||
/** 选择场景 */
|
/** 选择场景 */
|
||||||
selectScene: (sceneId: string) => void;
|
selectScene: (sceneId: string) => void;
|
||||||
/** 设置当前场景的AI文本和标签 */
|
/** 初始化当前选中场景的AI文本和标签数据 */
|
||||||
setCurrentSceneData: (text: TextItem, tags: TagItem[]) => void;
|
initializeSceneData: () => Promise<void>;
|
||||||
/** 优化AI文本 */
|
/** 优化AI文本 */
|
||||||
optimizeSceneText: () => Promise<void>;
|
optimizeSceneText: () => Promise<void>;
|
||||||
/** 修改AI文本 */
|
/** 修改AI文本 */
|
||||||
@ -85,48 +87,126 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
const [tagEditUseCases, setTagEditUseCases] = useState<Map<string, TagEditUseCase>>(new Map());
|
const [tagEditUseCases, setTagEditUseCases] = useState<Map<string, TagEditUseCase>>(new Map());
|
||||||
|
|
||||||
// 计算属性
|
// 计算属性
|
||||||
|
/**
|
||||||
|
* 场景图片URL
|
||||||
|
* @description 获取当前选中场景的图片URL
|
||||||
|
*/
|
||||||
const sceneImageUrl = useMemo(() => {
|
const sceneImageUrl = useMemo(() => {
|
||||||
return selectedScene?.entity.imageUrl || '';
|
return selectedScene?.entity.imageUrl || '';
|
||||||
}, [selectedScene]);
|
}, [selectedScene]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否全选分镜
|
||||||
|
* @description 判断是否所有分镜都被选中
|
||||||
|
*/
|
||||||
const isAllShotsSelected = useMemo(() => {
|
const isAllShotsSelected = useMemo(() => {
|
||||||
return shotSelectionList.length > 0 && shotSelectionList.every(shot => shot.selected);
|
return shotSelectionList.length > 0 && shotSelectionList.every(shot => shot.selected);
|
||||||
}, [shotSelectionList]);
|
}, [shotSelectionList]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已选中的分镜数量
|
||||||
|
* @description 获取当前选中的分镜数量
|
||||||
|
*/
|
||||||
const selectedShotsCount = useMemo(() => {
|
const selectedShotsCount = useMemo(() => {
|
||||||
return shotSelectionList.filter(shot => shot.selected).length;
|
return shotSelectionList.filter(shot => shot.selected).length;
|
||||||
}, [shotSelectionList]);
|
}, [shotSelectionList]);
|
||||||
|
|
||||||
// 选择场景
|
/**
|
||||||
const selectScene = useCallback((sceneId: string) => {
|
* 获取场景列表
|
||||||
|
* @description 根据项目ID获取所有场景列表
|
||||||
|
* @param projectId 项目ID
|
||||||
|
* @throws {Error} 当API调用失败时抛出错误
|
||||||
|
* @returns {Promise<void>} 获取完成后的Promise
|
||||||
|
*/
|
||||||
|
const fetchSceneList = useCallback(async (projectId: string) => {
|
||||||
|
try {
|
||||||
|
const response = await getSceneList({
|
||||||
|
projectId: projectId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.successful) {
|
||||||
|
const sceneItems = response.data.map(scene => new SceneItem(scene));
|
||||||
|
setSceneList(sceneItems);
|
||||||
|
} else {
|
||||||
|
throw new Error(`获取场景列表失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('获取场景列表失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 选择场景
|
||||||
|
* @description 根据场景ID选择场景,并初始化相关的UseCase实例
|
||||||
|
* @param sceneId 场景ID
|
||||||
|
*/
|
||||||
|
const selectScene = useCallback(async (sceneId: string) => {
|
||||||
const scene = sceneList.find(s => s.entity.id === sceneId);
|
const scene = sceneList.find(s => s.entity.id === sceneId);
|
||||||
if (scene) {
|
if (scene) {
|
||||||
setSelectedScene(scene);
|
setSelectedScene(scene);
|
||||||
|
|
||||||
|
// 初始化场景编辑UseCase实例
|
||||||
setSceneEditUseCase(new SceneEditUseCase(scene));
|
setSceneEditUseCase(new SceneEditUseCase(scene));
|
||||||
|
|
||||||
|
// 清空文本和标签相关状态
|
||||||
setTextEditUseCase(null);
|
setTextEditUseCase(null);
|
||||||
setTagEditUseCases(new Map());
|
setTagEditUseCases(new Map());
|
||||||
setCurrentSceneText(null);
|
setCurrentSceneText(null);
|
||||||
setCurrentSceneTags([]);
|
setCurrentSceneTags([]);
|
||||||
|
await initializeSceneData();
|
||||||
}
|
}
|
||||||
}, [sceneList]);
|
}, [sceneList]);
|
||||||
|
|
||||||
// 设置当前场景数据
|
/**
|
||||||
const setCurrentSceneData = useCallback((text: TextItem, tags: TagItem[]) => {
|
* 初始化场景数据
|
||||||
setCurrentSceneText(text);
|
* @description 初始化当前选中场景的AI文本和标签数据
|
||||||
setCurrentSceneTags(tags);
|
* @throws {Error} 当未选择场景或API调用失败时抛出错误
|
||||||
|
* @returns {Promise<void>} 初始化完成后的Promise
|
||||||
if (text) {
|
*/
|
||||||
setTextEditUseCase(new TextEditUseCase(text));
|
const initializeSceneData = useCallback(async () => {
|
||||||
|
if (!selectedScene) {
|
||||||
|
throw new Error('请先选择场景');
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTagEditUseCases = new Map<string, TagEditUseCase>();
|
try {
|
||||||
tags.forEach(tag => {
|
const response = await getSceneData({
|
||||||
newTagEditUseCases.set(tag.entity.id, new TagEditUseCase(tag));
|
sceneId: selectedScene.entity.id
|
||||||
});
|
});
|
||||||
setTagEditUseCases(newTagEditUseCases);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 优化AI文本
|
if (response.successful) {
|
||||||
|
const { text, tags } = response.data;
|
||||||
|
const textItem = new TextItem(text);
|
||||||
|
const tagItems = tags.map(tag => new TagItem(tag));
|
||||||
|
|
||||||
|
// 设置当前场景的AI文本和标签
|
||||||
|
setCurrentSceneText(textItem);
|
||||||
|
setCurrentSceneTags(tagItems);
|
||||||
|
|
||||||
|
// 初始化文本UseCase
|
||||||
|
setTextEditUseCase(new TextEditUseCase(textItem));
|
||||||
|
|
||||||
|
// 初始化标签UseCase
|
||||||
|
const newTagEditUseCases = new Map<string, TagEditUseCase>();
|
||||||
|
tagItems.forEach(tag => {
|
||||||
|
newTagEditUseCases.set(tag.entity.id, new TagEditUseCase(tag));
|
||||||
|
});
|
||||||
|
setTagEditUseCases(newTagEditUseCases);
|
||||||
|
} else {
|
||||||
|
throw new Error(`获取场景数据失败: ${response.message}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('初始化场景数据失败:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}, [selectedScene]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 优化AI文本
|
||||||
|
* @description 对当前场景的AI文本进行优化,无文本时不可进行优化
|
||||||
|
* @throws {Error} 当没有可优化的文本内容或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 优化完成后的Promise
|
||||||
|
*/
|
||||||
const optimizeSceneText = useCallback(async () => {
|
const optimizeSceneText = useCallback(async () => {
|
||||||
if (!textEditUseCase) {
|
if (!textEditUseCase) {
|
||||||
throw new Error('文本编辑UseCase未初始化');
|
throw new Error('文本编辑UseCase未初始化');
|
||||||
@ -141,7 +221,13 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
setCurrentSceneText(updatedTextItem);
|
setCurrentSceneText(updatedTextItem);
|
||||||
}, [textEditUseCase, currentSceneText]);
|
}, [textEditUseCase, currentSceneText]);
|
||||||
|
|
||||||
// 修改AI文本
|
/**
|
||||||
|
* 修改AI文本
|
||||||
|
* @description 手动修改当前场景的AI文本内容
|
||||||
|
* @param newContent 新的文本内容
|
||||||
|
* @throws {Error} 当没有可编辑的文本或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 修改完成后的Promise
|
||||||
|
*/
|
||||||
const updateSceneText = useCallback(async (newContent: string) => {
|
const updateSceneText = useCallback(async (newContent: string) => {
|
||||||
if (!textEditUseCase) {
|
if (!textEditUseCase) {
|
||||||
throw new Error('文本编辑UseCase未初始化');
|
throw new Error('文本编辑UseCase未初始化');
|
||||||
@ -155,7 +241,14 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
setCurrentSceneText(updatedTextItem);
|
setCurrentSceneText(updatedTextItem);
|
||||||
}, [textEditUseCase, currentSceneText]);
|
}, [textEditUseCase, currentSceneText]);
|
||||||
|
|
||||||
// 修改标签内容
|
/**
|
||||||
|
* 修改标签内容
|
||||||
|
* @description 修改指定标签的内容
|
||||||
|
* @param tagId 标签ID
|
||||||
|
* @param newContent 新的标签内容
|
||||||
|
* @throws {Error} 当标签不存在或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 修改完成后的Promise
|
||||||
|
*/
|
||||||
const updateTagContent = useCallback(async (tagId: string, newContent: string | number) => {
|
const updateTagContent = useCallback(async (tagId: string, newContent: string | number) => {
|
||||||
const tagEditUseCase = tagEditUseCases.get(tagId);
|
const tagEditUseCase = tagEditUseCases.get(tagId);
|
||||||
if (!tagEditUseCase) {
|
if (!tagEditUseCase) {
|
||||||
@ -173,7 +266,12 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
);
|
);
|
||||||
}, [tagEditUseCases]);
|
}, [tagEditUseCases]);
|
||||||
|
|
||||||
// 重新生成场景
|
/**
|
||||||
|
* 重新生成场景
|
||||||
|
* @description 使用AI文本和标签重新生成场景
|
||||||
|
* @throws {Error} 当缺少重新生成场景所需的数据或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 重新生成完成后的Promise
|
||||||
|
*/
|
||||||
const regenerateScene = useCallback(async () => {
|
const regenerateScene = useCallback(async () => {
|
||||||
if (!sceneEditUseCase) {
|
if (!sceneEditUseCase) {
|
||||||
throw new Error('场景编辑UseCase未初始化');
|
throw new Error('场景编辑UseCase未初始化');
|
||||||
@ -195,7 +293,12 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
);
|
);
|
||||||
}, [sceneEditUseCase, selectedScene, currentSceneText, currentSceneTags]);
|
}, [sceneEditUseCase, selectedScene, currentSceneText, currentSceneTags]);
|
||||||
|
|
||||||
// 获取场景分镜列表
|
/**
|
||||||
|
* 获取场景出现的分镜列表
|
||||||
|
* @description 获取当前场景应用到的分镜列表,包括已应用状态
|
||||||
|
* @throws {Error} 当未选择场景或API调用失败时抛出错误
|
||||||
|
* @returns {Promise<void>} 获取完成后的Promise
|
||||||
|
*/
|
||||||
const fetchSceneShots = useCallback(async () => {
|
const fetchSceneShots = useCallback(async () => {
|
||||||
if (!selectedScene) {
|
if (!selectedScene) {
|
||||||
throw new Error('请先选择场景');
|
throw new Error('请先选择场景');
|
||||||
@ -227,7 +330,10 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
}
|
}
|
||||||
}, [selectedScene]);
|
}, [selectedScene]);
|
||||||
|
|
||||||
// 切换全选与全不选
|
/**
|
||||||
|
* 切换全选与全不选
|
||||||
|
* @description 如果当前是全选状态则全不选,否则全选
|
||||||
|
*/
|
||||||
const toggleSelectAllShots = useCallback(() => {
|
const toggleSelectAllShots = useCallback(() => {
|
||||||
setShotSelectionList(prev => {
|
setShotSelectionList(prev => {
|
||||||
const isAllSelected = prev.length > 0 && prev.every(shot => shot.selected);
|
const isAllSelected = prev.length > 0 && prev.every(shot => shot.selected);
|
||||||
@ -235,7 +341,11 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 选择/取消选择单个分镜
|
/**
|
||||||
|
* 选择/取消选择单个分镜
|
||||||
|
* @description 切换指定分镜的选择状态
|
||||||
|
* @param shotId 分镜ID
|
||||||
|
*/
|
||||||
const toggleShotSelection = useCallback((shotId: string) => {
|
const toggleShotSelection = useCallback((shotId: string) => {
|
||||||
setShotSelectionList(prev =>
|
setShotSelectionList(prev =>
|
||||||
prev.map(shot =>
|
prev.map(shot =>
|
||||||
@ -246,7 +356,12 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
);
|
);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 应用场景到选中的分镜
|
/**
|
||||||
|
* 应用场景到选中的分镜
|
||||||
|
* @description 将当前场景应用到选中的分镜,并更新应用状态
|
||||||
|
* @throws {Error} 当未选择场景、未选择分镜或UseCase未初始化时抛出错误
|
||||||
|
* @returns {Promise<void>} 应用完成后的Promise
|
||||||
|
*/
|
||||||
const applySceneToSelectedShots = useCallback(async () => {
|
const applySceneToSelectedShots = useCallback(async () => {
|
||||||
if (!sceneEditUseCase) {
|
if (!sceneEditUseCase) {
|
||||||
throw new Error('场景编辑UseCase未初始化');
|
throw new Error('场景编辑UseCase未初始化');
|
||||||
@ -287,15 +402,27 @@ export const useSceneServiceHook = (): UseSceneService => {
|
|||||||
selectedShotsCount,
|
selectedShotsCount,
|
||||||
|
|
||||||
// 操作方法
|
// 操作方法
|
||||||
|
/** 获取场景列表 */
|
||||||
|
fetchSceneList,
|
||||||
|
/** 选择场景 */
|
||||||
selectScene,
|
selectScene,
|
||||||
setCurrentSceneData,
|
/** 初始化当前选中场景的AI文本和标签数据 */
|
||||||
|
initializeSceneData,
|
||||||
|
/** 优化AI文本 */
|
||||||
optimizeSceneText,
|
optimizeSceneText,
|
||||||
|
/** 修改AI文本 */
|
||||||
updateSceneText,
|
updateSceneText,
|
||||||
|
/** 修改标签内容 */
|
||||||
updateTagContent,
|
updateTagContent,
|
||||||
|
/** 重新生成场景 */
|
||||||
regenerateScene,
|
regenerateScene,
|
||||||
|
/** 获取场景出现的分镜列表 */
|
||||||
fetchSceneShots,
|
fetchSceneShots,
|
||||||
|
/** 切换全选与全不选 */
|
||||||
toggleSelectAllShots,
|
toggleSelectAllShots,
|
||||||
|
/** 选择/取消选择单个分镜 */
|
||||||
toggleShotSelection,
|
toggleShotSelection,
|
||||||
|
/** 应用场景到选中的分镜 */
|
||||||
applySceneToSelectedShots
|
applySceneToSelectedShots
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,6 @@ export interface BaseEntity {
|
|||||||
loadingProgress: number;
|
loadingProgress: number;
|
||||||
/** 禁止编辑 */
|
/** 禁止编辑 */
|
||||||
disableEdit: boolean;
|
disableEdit: boolean;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,7 +26,6 @@ export interface AITextEntity extends BaseEntity {
|
|||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色实体接口
|
* 角色实体接口
|
||||||
*/
|
*/
|
||||||
@ -40,6 +38,8 @@ export interface RoleEntity extends BaseEntity {
|
|||||||
tagIds: string[];
|
tagIds: string[];
|
||||||
/** 角色图片URL */
|
/** 角色图片URL */
|
||||||
imageUrl: string;
|
imageUrl: string;
|
||||||
|
/** 角色是否已存储 */
|
||||||
|
isStored: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,8 +66,6 @@ export interface SceneEntity extends BaseEntity {
|
|||||||
generateTextId: string;
|
generateTextId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface RoleMap {
|
interface RoleMap {
|
||||||
/** 角色ID */
|
/** 角色ID */
|
||||||
roleId: string;
|
roleId: string;
|
||||||
|
|||||||
3394
package-lock.json
generated
3394
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -106,7 +106,10 @@
|
|||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
"@types/lodash": "^4.17.19",
|
"@types/lodash": "^4.17.19",
|
||||||
"@types/react-grid-layout": "^1.3.5"
|
"@types/react-grid-layout": "^1.3.5",
|
||||||
|
"jest": "^30.0.5",
|
||||||
|
"ts-jest": "^29.4.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user