import { useState, useCallback, useMemo } from 'react'; import { VideoSegmentEntity } from '../domain/Entities'; import { RoleEditUseCase } from '../usecase/RoleEditUseCase'; import { getRoleShots, applyRoleToShots } from '@/api/video_flow'; /** * 扩展的视频片段实体,包含选择状态 */ interface ExtendedVideoSegmentEntity extends VideoSegmentEntity { /** 是否已选中 */ selected?: boolean; /** 是否已应用角色 */ applied?: boolean; } /** * 角色视频片段服务Hook返回值接口 */ interface UseRoleShotService { // 响应式数据 /** 分镜选择列表 */ shotSelectionList: ExtendedVideoSegmentEntity[]; /** 是否全选分镜 */ isAllVideoSegmentSelected: boolean; /** 已选中的分镜数量 */ selectedVideoSegmentCount: number; /** 当前选中的角色ID */ selectedRoleId: string | null; // 操作方法 /** 获取角色出现的分镜列表 */ fetchRoleShots: (roleId: string) => Promise; /** 切换全选与全不选 */ toggleSelectAllShots: () => void; /** 选择/取消选择单个分镜 */ toggleShotSelection: (shotId: string) => void; /** 应用角色到选中的分镜 */ applyRoleToSelectedShots: (roleId: string) => Promise; /** 清空选择列表 */ clearShotSelection: () => void; } /** * 角色视频片段服务Hook * 提供角色与视频片段交互的所有响应式功能和业务逻辑 */ export const useRoleShotServiceHook = (): UseRoleShotService => { // 响应式状态 const [shotSelectionList, setShotSelectionList] = useState([]); const [selectedRoleId, setSelectedRoleId] = useState(null); // UseCase实例 const [roleEditUseCase, setRoleEditUseCase] = useState(null); // 计算属性 /** * 是否全选分镜 * @description 判断是否所有分镜都被选中 */ const isAllVideoSegmentSelected = useMemo(() => { return shotSelectionList.length > 0 && shotSelectionList.every(shot => shot.selected); }, [shotSelectionList]); /** * 已选中的分镜数量 * @description 获取当前选中的分镜数量 */ const selectedVideoSegmentCount = useMemo(() => { return shotSelectionList.filter(shot => shot.selected).length; }, [shotSelectionList]); /** * 获取角色出现的分镜列表 * @description 获取当前角色应用到的分镜列表,包括已应用状态 * @param roleId 角色ID * @throws {Error} 当API调用失败时抛出错误 * @returns {Promise} 获取完成后的Promise */ const fetchRoleShots = useCallback(async (roleId: string) => { try { const response = await getRoleShots({ roleId }); if (response.successful) { const { shots, appliedShotIds } = response.data; const extendedShots: ExtendedVideoSegmentEntity[] = shots.map(shot => ({ ...shot, selected: false, applied: appliedShotIds.includes(shot.id) })); setShotSelectionList(extendedShots); setSelectedRoleId(roleId); // 初始化角色编辑UseCase实例 const newRoleEditUseCase = new RoleEditUseCase(); setRoleEditUseCase(newRoleEditUseCase); } else { throw new Error(`获取角色分镜列表失败: ${response.message}`); } } catch (error) { console.error('获取角色分镜列表失败:', error); throw error; } }, []); /** * 切换全选与全不选 * @description 如果当前是全选状态则全不选,否则全选 */ const toggleSelectAllShots = useCallback(() => { setShotSelectionList(prev => { const isAllSelected = prev.length > 0 && prev.every(shot => shot.selected); return prev.map(shot => ({ ...shot, selected: !isAllSelected })); }); }, []); /** * 选择/取消选择单个分镜 * @description 切换指定分镜的选择状态 * @param shotId 分镜ID */ const toggleShotSelection = useCallback((shotId: string) => { setShotSelectionList(prev => prev.map(shot => shot.id === shotId ? { ...shot, selected: !shot.selected } : shot ) ); }, []); /** * 应用角色到选中的分镜 * @description 将当前角色应用到选中的分镜,并更新应用状态 * @param roleId 角色ID * @throws {Error} 当未选择分镜或UseCase未初始化时抛出错误 * @returns {Promise} 应用完成后的Promise */ const applyRoleToSelectedShots = useCallback(async (roleId: string) => { if (!roleEditUseCase) { throw new Error('角色编辑UseCase未初始化'); } const selectedShotIds = shotSelectionList .filter(shot => shot.selected) .map(shot => shot.id); if (selectedShotIds.length === 0) { throw new Error('请先选择要应用的分镜'); } try { await roleEditUseCase.applyRole(selectedShotIds, roleId); // 更新应用状态 setShotSelectionList(prev => prev.map(shot => selectedShotIds.includes(shot.id) ? { ...shot, applied: true, selected: false } : shot ) ); } catch (error) { console.error('应用角色到分镜失败:', error); throw error; } }, [roleEditUseCase, shotSelectionList]); /** * 清空选择列表 * @description 清空所有分镜的选择状态 */ const clearShotSelection = useCallback(() => { setShotSelectionList(prev => prev.map(shot => ({ ...shot, selected: false })) ); }, []); return { // 响应式数据 shotSelectionList, isAllVideoSegmentSelected, selectedVideoSegmentCount, selectedRoleId, // 操作方法 fetchRoleShots, toggleSelectAllShots, toggleShotSelection, applyRoleToSelectedShots, clearShotSelection, }; };