forked from 77media/video-flow
检测角色改变
This commit is contained in:
parent
90fb57f0fd
commit
e6ef62a3d7
@ -43,6 +43,7 @@ export const useEditData = (tabType: string, originalText?: string) => {
|
|||||||
regenerateRole,
|
regenerateRole,
|
||||||
uploadImageAndUpdateRole,
|
uploadImageAndUpdateRole,
|
||||||
saveRoleToLibrary,
|
saveRoleToLibrary,
|
||||||
|
changeTabCallback,
|
||||||
} = useRoleServiceHook();
|
} = useRoleServiceHook();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@ -134,6 +135,7 @@ export const useEditData = (tabType: string, originalText?: string) => {
|
|||||||
regenerateRole,
|
regenerateRole,
|
||||||
fetchUserRoleLibrary,
|
fetchUserRoleLibrary,
|
||||||
uploadImageAndUpdateRole,
|
uploadImageAndUpdateRole,
|
||||||
|
changeTabCallback,
|
||||||
// role shot
|
// role shot
|
||||||
shotSelectionList,
|
shotSelectionList,
|
||||||
selectedRoleId,
|
selectedRoleId,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect, forwardRef } from 'react';
|
||||||
import { motion, AnimatePresence } from 'framer-motion';
|
import { motion, AnimatePresence } from 'framer-motion';
|
||||||
import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, CircleX, ReplaceAll, X, TriangleAlert, Loader2 } from 'lucide-react';
|
import { ImageUp, Library, Play, Pause, RefreshCw, Wand2, Users, CircleX, ReplaceAll, X, TriangleAlert, Loader2 } from 'lucide-react';
|
||||||
import { cn } from '@/public/lib/utils';
|
import { cn } from '@/public/lib/utils';
|
||||||
@ -35,18 +35,17 @@ interface Role {
|
|||||||
|
|
||||||
|
|
||||||
interface CharacterTabContentProps {
|
interface CharacterTabContentProps {
|
||||||
taskSketch: any[];
|
onClose: () => void;
|
||||||
currentRoleIndex: number;
|
onApply: () => void;
|
||||||
onSketchSelect: (index: number) => void;
|
setActiveTab: (tabId: string) => void;
|
||||||
roles: Role[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CharacterTabContent({
|
|
||||||
taskSketch,
|
export const CharacterTabContent = forwardRef<
|
||||||
currentRoleIndex,
|
{ switchBefore: (tabId: string) => boolean, saveBefore: () => void },
|
||||||
onSketchSelect,
|
CharacterTabContentProps
|
||||||
roles = []
|
>((props, ref) => {
|
||||||
}: CharacterTabContentProps) {
|
const { onClose, onApply, setActiveTab } = props;
|
||||||
const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false);
|
const [isReplacePanelOpen, setIsReplacePanelOpen] = useState(false);
|
||||||
const [replacePanelKey, setReplacePanelKey] = useState(0);
|
const [replacePanelKey, setReplacePanelKey] = useState(0);
|
||||||
const [ignoreReplace, setIgnoreReplace] = useState(false);
|
const [ignoreReplace, setIgnoreReplace] = useState(false);
|
||||||
@ -61,6 +60,10 @@ export function CharacterTabContent({
|
|||||||
const [isLoadingShots, setIsLoadingShots] = useState(false);
|
const [isLoadingShots, setIsLoadingShots] = useState(false);
|
||||||
const [isLoadingLibrary, setIsLoadingLibrary] = useState(false);
|
const [isLoadingLibrary, setIsLoadingLibrary] = useState(false);
|
||||||
const [isUploading, setIsUploading] = useState(false);
|
const [isUploading, setIsUploading] = useState(false);
|
||||||
|
const [isUpdate, setIsUpdate] = useState(false);
|
||||||
|
const [triggerType, setTriggerType] = useState<'tab' | 'apply' | 'user'>('tab');
|
||||||
|
const [nextToTabId, setNextToTabId] = useState<string>('');
|
||||||
|
const [nextToUserIndex, setNextToUserIndex] = useState<number>(-1);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
loading,
|
loading,
|
||||||
@ -73,6 +76,7 @@ export function CharacterTabContent({
|
|||||||
regenerateRole,
|
regenerateRole,
|
||||||
fetchUserRoleLibrary,
|
fetchUserRoleLibrary,
|
||||||
uploadImageAndUpdateRole,
|
uploadImageAndUpdateRole,
|
||||||
|
changeTabCallback,
|
||||||
// role shot
|
// role shot
|
||||||
shotSelectionList,
|
shotSelectionList,
|
||||||
fetchRoleShots,
|
fetchRoleShots,
|
||||||
@ -82,6 +86,31 @@ export function CharacterTabContent({
|
|||||||
const searchParams = useSearchParams();
|
const searchParams = useSearchParams();
|
||||||
const episodeId = searchParams.get('episodeId');
|
const episodeId = searchParams.get('episodeId');
|
||||||
|
|
||||||
|
// 暴露方法给父组件
|
||||||
|
React.useImperativeHandle(ref, () => ({
|
||||||
|
switchBefore: (tabId: string) => {
|
||||||
|
setNextToTabId(tabId);
|
||||||
|
// 判断 角色是否修改
|
||||||
|
const isChange = selectedRole!.isChangeRole
|
||||||
|
console.log('switchBefore', isChange);
|
||||||
|
if (isChange) {
|
||||||
|
setTriggerType('tab');
|
||||||
|
setIsRemindReplacePanelOpen(true);
|
||||||
|
}
|
||||||
|
return isChange;
|
||||||
|
},
|
||||||
|
saveBefore: () => {
|
||||||
|
console.log('saveBefore');
|
||||||
|
// 判断 角色是否修改
|
||||||
|
changeTabCallback((isChange: Boolean) => {
|
||||||
|
if (isChange) {
|
||||||
|
setTriggerType('apply');
|
||||||
|
handleStartReplaceCharacter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('-==========roleData===========-', roleData);
|
console.log('-==========roleData===========-', roleData);
|
||||||
@ -116,24 +145,32 @@ export function CharacterTabContent({
|
|||||||
|
|
||||||
const handleConfirmGotoReplace = () => {
|
const handleConfirmGotoReplace = () => {
|
||||||
setIsRemindReplacePanelOpen(false);
|
setIsRemindReplacePanelOpen(false);
|
||||||
setIsReplacePanelOpen(true);
|
handleStartReplaceCharacter();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCloseRemindReplacePanel = () => {
|
const handleCloseRemindReplacePanel = () => {
|
||||||
setIsRemindReplacePanelOpen(false);
|
setIsRemindReplacePanelOpen(false);
|
||||||
setIgnoreReplace(true);
|
console.log('忽略替换', triggerType, nextToTabId, nextToUserIndex);
|
||||||
|
if (triggerType === 'apply') {
|
||||||
|
onClose();
|
||||||
|
} else if (triggerType === 'tab') {
|
||||||
|
setActiveTab(nextToTabId);
|
||||||
|
} else {
|
||||||
|
selectRole(roleData[nextToUserIndex]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// President Alfred King Samuel Ryan
|
// President Alfred King Samuel Ryan
|
||||||
const handleConfirmReplace = (selectedShots: string[], addToLibrary: boolean) => {
|
const handleConfirmReplace = async (selectedShots: string[], addToLibrary: boolean) => {
|
||||||
// 处理替换确认逻辑
|
// 处理替换确认逻辑
|
||||||
console.log('Selected shots:', selectedShots);
|
console.log('Selected shots:', selectedShots);
|
||||||
console.log('Add to library:', addToLibrary);
|
console.log('Add to library:', addToLibrary);
|
||||||
applyRoleToSelectedShots(selectedRole || {} as RoleEntity);
|
await applyRoleToSelectedShots(selectedRole || {} as RoleEntity);
|
||||||
setIsReplacePanelOpen(false);
|
setIsReplacePanelOpen(false);
|
||||||
if(addToLibrary){
|
if(addToLibrary){
|
||||||
saveRoleToLibrary();
|
saveRoleToLibrary();
|
||||||
}
|
}
|
||||||
|
onApply();
|
||||||
};
|
};
|
||||||
|
|
||||||
// 取消替换
|
// 取消替换
|
||||||
@ -143,18 +180,22 @@ export function CharacterTabContent({
|
|||||||
|
|
||||||
const handleChangeRole = (index: number) => {
|
const handleChangeRole = (index: number) => {
|
||||||
const oldRole = roleData.find(role => role.id === selectedRole?.id);
|
const oldRole = roleData.find(role => role.id === selectedRole?.id);
|
||||||
console.log('切换角色前对比', selectedRole?.imageUrl, oldRole?.imageUrl);
|
console.log('切换角色前对比');
|
||||||
if (selectedRole?.imageUrl !== oldRole?.imageUrl && !ignoreReplace) {
|
changeTabCallback((isChange: Boolean) => {
|
||||||
// 提示 角色已修改,弹出替换角色面板
|
if (isChange) {
|
||||||
setIsRemindReplacePanelOpen(true);
|
setTriggerType('user');
|
||||||
return;
|
setIsRemindReplacePanelOpen(true);
|
||||||
}
|
setNextToUserIndex(index);
|
||||||
// 重置替换规则
|
return;
|
||||||
setEnableAnimation(false);
|
}
|
||||||
setIgnoreReplace(false);
|
|
||||||
setIsRegenerate(false);
|
|
||||||
|
|
||||||
selectRole(roleData[index]);
|
// 重置替换规则
|
||||||
|
setEnableAnimation(false);
|
||||||
|
setIgnoreReplace(false);
|
||||||
|
setIsRegenerate(false);
|
||||||
|
|
||||||
|
selectRole(roleData[index]);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 从角色库中选择角色
|
// 从角色库中选择角色
|
||||||
@ -172,7 +213,7 @@ export function CharacterTabContent({
|
|||||||
...role,
|
...role,
|
||||||
name: selectedRole?.name || ''
|
name: selectedRole?.name || ''
|
||||||
});
|
});
|
||||||
handleStartReplaceCharacter();
|
// handleStartReplaceCharacter();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,7 +235,7 @@ export function CharacterTabContent({
|
|||||||
// 然后调用重新生成角色
|
// 然后调用重新生成角色
|
||||||
await regenerateRole();
|
await regenerateRole();
|
||||||
setIsRegenerate(false);
|
setIsRegenerate(false);
|
||||||
handleStartReplaceCharacter();
|
// handleStartReplaceCharacter();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleUploadClick = () => {
|
const handleUploadClick = () => {
|
||||||
@ -347,17 +388,7 @@ export function CharacterTabContent({
|
|||||||
onUpdateText={(text: string) => updateRoleText(text)}
|
onUpdateText={(text: string) => updateRoleText(text)}
|
||||||
/>
|
/>
|
||||||
{/* 重新生成按钮、替换形象按钮 */}
|
{/* 重新生成按钮、替换形象按钮 */}
|
||||||
<div className="grid grid-cols-2 gap-2">
|
<div className="grid grid-cols-1 gap-2">
|
||||||
<motion.button
|
|
||||||
onClick={() => handleStartReplaceCharacter()}
|
|
||||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-pink-500/10 hover:bg-pink-500/20
|
|
||||||
text-pink-500 rounded-lg transition-colors"
|
|
||||||
whileHover={{ scale: 1.02 }}
|
|
||||||
whileTap={{ scale: 0.98 }}
|
|
||||||
>
|
|
||||||
<ReplaceAll className="w-4 h-4" />
|
|
||||||
<span>Replace</span>
|
|
||||||
</motion.button>
|
|
||||||
<motion.button
|
<motion.button
|
||||||
onClick={() => handleRegenerate()}
|
onClick={() => handleRegenerate()}
|
||||||
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-500/10 hover:bg-blue-500/20
|
className="flex items-center justify-center gap-2 px-4 py-3 bg-blue-500/10 hover:bg-blue-500/20
|
||||||
@ -410,7 +441,7 @@ export function CharacterTabContent({
|
|||||||
<div className="flex flex-col items-center gap-4 text-white py-4">
|
<div className="flex flex-col items-center gap-4 text-white py-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<TriangleAlert className="w-6 h-6 text-yellow-400" />
|
<TriangleAlert className="w-6 h-6 text-yellow-400" />
|
||||||
<p className="text-lg font-medium">角色已修改,是否需要替换?</p>
|
<p className="text-lg font-medium">角色已修改,不替换就会丢失修改,是否需要替换?</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-3 mt-2">
|
<div className="flex gap-3 mt-2">
|
||||||
@ -436,4 +467,4 @@ export function CharacterTabContent({
|
|||||||
</FloatingGlassPanel>
|
</FloatingGlassPanel>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export function EditModal({
|
|||||||
const [resetKey, setResetKey] = useState(0);
|
const [resetKey, setResetKey] = useState(0);
|
||||||
const [remindFallbackText, setRemindFallbackText] = useState('The task will be regenerated and edited. Do you want to continue?');
|
const [remindFallbackText, setRemindFallbackText] = useState('The task will be regenerated and edited. Do you want to continue?');
|
||||||
const scriptTabContentRef = useRef<any>(null);
|
const scriptTabContentRef = useRef<any>(null);
|
||||||
|
const characterTabContentRef = useRef<any>(null);
|
||||||
// 添加一个状态来标记是否是从切换tab触发的提醒
|
// 添加一个状态来标记是否是从切换tab触发的提醒
|
||||||
const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null);
|
const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null);
|
||||||
|
|
||||||
@ -97,11 +98,16 @@ const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null
|
|||||||
}
|
}
|
||||||
|
|
||||||
const checkUpdate = (tabId: string) => {
|
const checkUpdate = (tabId: string) => {
|
||||||
if (tabId === '0') {
|
if (activeTab === '0') {
|
||||||
const scriptTabContent = scriptTabContentRef.current;
|
const scriptTabContent = scriptTabContentRef.current;
|
||||||
if (scriptTabContent) {
|
if (scriptTabContent) {
|
||||||
return scriptTabContent.checkUpdate();
|
return scriptTabContent.checkUpdate();
|
||||||
}
|
}
|
||||||
|
} else if (activeTab === '1') {
|
||||||
|
const characterTabContent = characterTabContentRef.current;
|
||||||
|
if (characterTabContent) {
|
||||||
|
return characterTabContent.switchBefore(tabId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -109,11 +115,11 @@ const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null
|
|||||||
const handleChangeTab = (tabId: string, disabled: boolean) => {
|
const handleChangeTab = (tabId: string, disabled: boolean) => {
|
||||||
if (disabled) return;
|
if (disabled) return;
|
||||||
// 切换前 检查是否更新
|
// 切换前 检查是否更新
|
||||||
const isUpdate = checkUpdate(activeTab);
|
const isUpdate = checkUpdate(tabId);
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
setPendingSwitchTabId(tabId); // 记录要切换到的目标tab
|
// setPendingSwitchTabId(tabId); // 记录要切换到的目标tab
|
||||||
setRemindFallbackText('You must click Apply button to save the current changes.');
|
// setRemindFallbackText('You must click Apply button to save the current changes.');
|
||||||
setIsRemindFallbackOpen(true);
|
// setIsRemindFallbackOpen(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setActiveTab(tabId);
|
setActiveTab(tabId);
|
||||||
@ -122,7 +128,15 @@ const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null
|
|||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
console.log('handleSave');
|
console.log('handleSave');
|
||||||
setIsRemindFallbackOpen(true);
|
// setIsRemindFallbackOpen(true);
|
||||||
|
if (activeTab === '1') {
|
||||||
|
characterTabContentRef.current.saveBefore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleApply = () => {
|
||||||
|
console.log('handleApply');
|
||||||
|
handleConfirmGotoFallback();
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleConfirmGotoFallback = () => {
|
const handleConfirmGotoFallback = () => {
|
||||||
@ -174,10 +188,10 @@ const [pendingSwitchTabId, setPendingSwitchTabId] = useState<string | null>(null
|
|||||||
case '1':
|
case '1':
|
||||||
return (
|
return (
|
||||||
<CharacterTabContent
|
<CharacterTabContent
|
||||||
taskSketch={taskSketch}
|
ref={characterTabContentRef}
|
||||||
currentRoleIndex={currentRoleIndex}
|
onClose={onClose}
|
||||||
onSketchSelect={hanldeChangeSelect}
|
onApply={handleApply}
|
||||||
roles={roles}
|
setActiveTab={setActiveTab}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case '2':
|
case '2':
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user