forked from 77media/video-flow
362 lines
11 KiB
TypeScript
362 lines
11 KiB
TypeScript
import { useState, useCallback, useMemo } from 'react';
|
||
import { RoleEntity, AITextEntity } from '../domain/Entities';
|
||
import { RoleEditUseCase } from '../usecase/RoleEditUseCase';
|
||
import { getUploadToken, uploadToQiniu } from '@/api/common';
|
||
|
||
/**
|
||
* 角色服务Hook返回值接口
|
||
*/
|
||
interface UseRoleService {
|
||
// 响应式数据
|
||
/** 角色列表 */
|
||
roleList: RoleEntity[];
|
||
/** 当前选中的角色 */
|
||
selectedRole: RoleEntity | null;
|
||
/** 当前角色的AI文本 */
|
||
currentRoleText: string | null;
|
||
/** 角色图片URL */
|
||
roleImageUrl: string;
|
||
/** 用户角色库 */
|
||
userRoleLibrary: RoleEntity[];
|
||
// 操作方法
|
||
/** 获取角色列表 */
|
||
fetchRoleList: (projectId: string) => Promise<void>;
|
||
/** 选择角色 */
|
||
selectRole: (roleId: string) => Promise<void>;
|
||
/** 优化AI文本 */
|
||
optimizeRoleText: (userSuggestion: string) => Promise<void>;
|
||
/** 修改AI文本 */
|
||
updateRoleText: (newContent: string) => Promise<void>;
|
||
/** 重新生成角色 */
|
||
regenerateRole: () => Promise<void>;
|
||
/** 获取用户角色库 */
|
||
fetchUserRoleLibrary: () => Promise<void>;
|
||
/** 替换角色 */
|
||
replaceRoleWithLibrary: (replaceRoleId: string) => Promise<void>;
|
||
/** 上传图片到七牛云 */
|
||
uploadImageToQiniu: (file: File) => Promise<void>;
|
||
}
|
||
|
||
/**
|
||
* 角色服务Hook
|
||
* 提供角色相关的所有响应式功能和业务逻辑
|
||
*/
|
||
export const useRoleServiceHook = (): UseRoleService => {
|
||
// 响应式状态
|
||
const [roleList, setRoleList] = useState<RoleEntity[]>([]);
|
||
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状态
|
||
|
||
// UseCase实例 - 在角色选择时初始化
|
||
const [roleEditUseCase, setRoleEditUseCase] = useState<RoleEditUseCase | null>(null);
|
||
|
||
// 计算属性
|
||
/**
|
||
* 角色图片URL
|
||
* @description 获取当前选中角色的图片URL
|
||
*/
|
||
const roleImageUrl = useMemo(() => {
|
||
return selectedRole?.imageUrl || '';
|
||
}, [selectedRole]);
|
||
|
||
/**
|
||
* 获取角色列表
|
||
* @description 根据项目ID获取所有角色列表
|
||
* @param projectId 项目ID
|
||
* @throws {Error} 当API调用失败时抛出错误
|
||
* @returns {Promise<void>} 获取完成后的Promise
|
||
*/
|
||
const fetchRoleList = useCallback(async (projectId: string) => {
|
||
try {
|
||
// 保存项目ID到状态
|
||
setProjectId(projectId);
|
||
|
||
// 初始化角色编辑UseCase实例
|
||
const newRoleEditUseCase = new RoleEditUseCase();
|
||
const roleList = await newRoleEditUseCase.getRoleList(projectId);
|
||
|
||
setRoleList(roleList);
|
||
setRoleEditUseCase(newRoleEditUseCase);
|
||
} catch (error) {
|
||
console.error('获取角色列表失败:', error);
|
||
throw error;
|
||
}
|
||
}, []);
|
||
|
||
/**
|
||
* 初始化角色数据
|
||
* @description 初始化当前选中角色的AI文本数据
|
||
* @param roleId 角色ID
|
||
* @throws {Error} 当未选择角色或API调用失败时抛出错误
|
||
* @returns {Promise<void>} 初始化完成后的Promise
|
||
*/
|
||
const initializeRoleData = useCallback(async (roleId: string) => {
|
||
|
||
}, []);
|
||
|
||
/**
|
||
* 选择角色
|
||
* @description 根据角色ID选择角色,并初始化相关的UseCase实例
|
||
* @param roleId 角色ID
|
||
*/
|
||
const selectRole = useCallback(async (roleId: string) => {
|
||
const role = roleList.find(r => r.id === roleId);
|
||
if (role) {
|
||
setSelectedRole(role);
|
||
|
||
// 如果RoleEditUseCase已经初始化,直接使用;否则创建新的
|
||
if (!roleEditUseCase) {
|
||
const newRoleEditUseCase = new RoleEditUseCase();
|
||
newRoleEditUseCase.roleList = roleList;
|
||
setRoleEditUseCase(newRoleEditUseCase);
|
||
}
|
||
|
||
// 调用selectRole方法
|
||
await roleEditUseCase!.selectRole(roleId);
|
||
|
||
// 初始化角色数据
|
||
await initializeRoleData(roleId);
|
||
} else {
|
||
throw new Error('未找到对应的角色');
|
||
}
|
||
}, [roleList, roleEditUseCase, initializeRoleData]);
|
||
|
||
/**
|
||
* 优化AI文本
|
||
* @description 对当前角色的AI文本进行优化
|
||
* @throws {Error} 当没有可优化的文本内容或UseCase未初始化时抛出错误
|
||
* @returns {Promise<void>} 优化完成后的Promise
|
||
*/
|
||
const optimizeRoleText = useCallback(async () => {
|
||
if (!roleEditUseCase) {
|
||
throw new Error('角色编辑UseCase未初始化');
|
||
}
|
||
|
||
if (!currentRoleText) {
|
||
throw new Error('没有可优化的文本内容');
|
||
}
|
||
|
||
if (!selectedRole) {
|
||
throw new Error('没有选中的角色');
|
||
}
|
||
|
||
try {
|
||
const { optimizedDescription, keywords } = await roleEditUseCase.optimizeRoleDescription(selectedRole);
|
||
setCurrentRoleText(optimizedDescription);
|
||
// 更新角色列表中的对应角色描述和标签
|
||
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)}`,
|
||
/** 名称 */
|
||
name: keyword,
|
||
/** 内容 */
|
||
content: keyword,
|
||
loadingProgress: 100,
|
||
disableEdit: false
|
||
}))
|
||
}
|
||
: role
|
||
)
|
||
);
|
||
|
||
// 更新当前选中角色
|
||
if (selectedRole) {
|
||
setSelectedRole({ ...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);
|
||
throw error;
|
||
}
|
||
}, [roleEditUseCase, currentRoleText, selectedRole]);
|
||
|
||
/**
|
||
* 修改AI文本
|
||
* @description 手动修改当前角色的AI文本内容
|
||
* @param newContent 新的文本内容
|
||
* @throws {Error} 当没有可编辑的文本或UseCase未初始化时抛出错误
|
||
* @returns {Promise<void>} 修改完成后的Promise
|
||
*/
|
||
const updateRoleText = useCallback(async (newContent: string) => {
|
||
if (!roleEditUseCase) {
|
||
throw new Error('角色编辑UseCase未初始化');
|
||
}
|
||
|
||
setCurrentRoleText(newContent);
|
||
|
||
// 更新角色列表中的对应角色描述
|
||
setRoleList(prev =>
|
||
prev.map(role =>
|
||
role.id === selectedRole?.id
|
||
? { ...role, generateText: newContent }
|
||
: role
|
||
)
|
||
);
|
||
|
||
// 更新当前选中角色
|
||
if (selectedRole) {
|
||
setSelectedRole({ ...selectedRole, generateText: newContent });
|
||
}
|
||
}, [roleEditUseCase, selectedRole]);
|
||
|
||
/**
|
||
* 重新生成角色
|
||
* @description 使用AI文本重新生成角色
|
||
* @throws {Error} 当缺少重新生成角色所需的数据或UseCase未初始化时抛出错误
|
||
* @returns {Promise<void>} 重新生成完成后的Promise
|
||
*/
|
||
const regenerateRole = useCallback(async () => {
|
||
if (!roleEditUseCase) {
|
||
throw new Error('角色编辑UseCase未初始化');
|
||
}
|
||
|
||
if (!selectedRole || !currentRoleText) {
|
||
throw new Error('缺少重新生成角色所需的数据');
|
||
}
|
||
|
||
if (!projectId) {
|
||
throw new Error('缺少项目ID,无法重新生成角色');
|
||
}
|
||
|
||
try {
|
||
const newRoleEntity = await roleEditUseCase.AIgenerateRole(
|
||
projectId,
|
||
selectedRole.name,
|
||
currentRoleText
|
||
);
|
||
setSelectedRole(newRoleEntity);
|
||
|
||
// 更新角色列表
|
||
setRoleList(prev =>
|
||
prev.map(role =>
|
||
role.id === newRoleEntity.id
|
||
? newRoleEntity
|
||
: role
|
||
)
|
||
);
|
||
} catch (error) {
|
||
console.error('重新生成角色失败:', error);
|
||
throw error;
|
||
}
|
||
}, [roleEditUseCase, selectedRole, currentRoleText, projectId]);
|
||
|
||
/**
|
||
* 获取用户角色库
|
||
* @description 获取当前用户的角色库列表
|
||
* @throws {Error} 当API调用失败时抛出错误
|
||
* @returns {Promise<void>} 获取完成后的Promise
|
||
*/
|
||
const fetchUserRoleLibrary = useCallback(async () => {
|
||
try {
|
||
// 如果没有初始化RoleEditUseCase,创建一个新的实例
|
||
if (!roleEditUseCase) {
|
||
const newRoleEditUseCase = new RoleEditUseCase();
|
||
setRoleEditUseCase(newRoleEditUseCase);
|
||
}
|
||
|
||
const roleLibraryList = await roleEditUseCase!.getRoleLibraryList();
|
||
setUserRoleLibrary(roleLibraryList);
|
||
} catch (error) {
|
||
console.error('获取用户角色库失败:', error);
|
||
throw error;
|
||
}
|
||
}, [roleEditUseCase]);
|
||
|
||
/**
|
||
* 替换角色
|
||
* @description 使用角色库中的角色替换当前角色,并重新获取角色详细数据
|
||
* @param replaceRoleId 替换的角色ID
|
||
* @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);
|
||
|
||
// 重新获取角色数据
|
||
await initializeRoleData(selectedRole.id);
|
||
|
||
// 更新角色列表
|
||
const libraryRole = userRoleLibrary.find(role => role.id === replaceRoleId);
|
||
if (libraryRole) {
|
||
const updatedRole = {
|
||
...selectedRole,
|
||
name: libraryRole.name,
|
||
generateText: libraryRole.generateText,
|
||
imageUrl: libraryRole.imageUrl,
|
||
};
|
||
|
||
setSelectedRole(updatedRole);
|
||
setRoleList(prev =>
|
||
prev.map(role =>
|
||
role.id === selectedRole.id
|
||
? updatedRole
|
||
: role
|
||
)
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('替换角色失败:', error);
|
||
throw error;
|
||
}
|
||
}, [selectedRole, roleEditUseCase, userRoleLibrary, initializeRoleData]);
|
||
|
||
/**
|
||
* 上传图片到七牛云
|
||
* @description 上传图片文件到七牛云存储
|
||
* @param file 要上传的文件
|
||
* @returns {Promise<string>} 上传成功后的图片URL
|
||
*/
|
||
const uploadImageToQiniu = useCallback(async (file: File) => {
|
||
try {
|
||
const { token } = await getUploadToken();
|
||
const url = await uploadToQiniu(file, token);
|
||
const roleEntity = await roleEditUseCase?.getRoleByImage(url);
|
||
} catch (error) {
|
||
console.error('上传图片到七牛云失败:', error);
|
||
throw error;
|
||
}
|
||
}, [roleEditUseCase]);
|
||
|
||
return {
|
||
// 响应式数据
|
||
roleList,
|
||
selectedRole,
|
||
currentRoleText,
|
||
roleImageUrl,
|
||
userRoleLibrary,
|
||
|
||
// 操作方法
|
||
fetchRoleList,
|
||
selectRole,
|
||
optimizeRoleText,
|
||
updateRoleText,
|
||
regenerateRole,
|
||
fetchUserRoleLibrary,
|
||
replaceRoleWithLibrary,
|
||
uploadImageToQiniu
|
||
};
|
||
};
|