报错提示修复,样式优化

This commit is contained in:
海龙 2025-08-21 22:27:16 +08:00
parent 2c88b8201b
commit e405f4bd7d
6 changed files with 148 additions and 71 deletions

View File

@ -60,7 +60,11 @@ export interface CreateMovieProjectV2Request {
/** 类型 */ /** 类型 */
genre: string; genre: string;
/** 角色简介数组 */ /** 角色简介数组 */
character_briefs: string[]; character_briefs: {
name:string;
image_url:string;
character_analysis:Record<string,any>;
}[];
/** 语言 */ /** 语言 */
language: string; language: string;
/** 图片URL */ /** 图片URL */

View File

@ -30,7 +30,7 @@ request.interceptors.request.use(
request.interceptors.response.use( request.interceptors.response.use(
(response: AxiosResponse) => { (response: AxiosResponse) => {
// 直接返回响应数据 // 直接返回响应数据
if (!response.data?.successful) { if (response.data?.code !=0) {
// TODO 暂时固定报错信息,后续根据后端返回的错误码进行处理 // TODO 暂时固定报错信息,后续根据后端返回的错误码进行处理
errorHandle(0); errorHandle(0);
} }

View File

@ -426,9 +426,11 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
// 从charactersAnalysis中提取whisk_caption字段组成数组 // 从charactersAnalysis中提取whisk_caption字段组成数组
const character_briefs = charactersAnalysis.map(char => { const character_briefs = charactersAnalysis.map(char => {
const obj = JSON.parse(char.whisk_caption); return {
obj.character_analysis.role_name = char.role_name; name:char.role_name,
return JSON.stringify(obj); image_url:char.crop_url,
character_analysis:JSON.parse(char.whisk_caption).character_analysis
}
}); });
const params: CreateMovieProjectV2Request = { const params: CreateMovieProjectV2Request = {

View File

@ -142,7 +142,7 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => {
] ]
} }
]); ]);
}, 10000); }, 3000);
}); });
setTemplateStoryList(templates); setTemplateStoryList(templates);

View File

@ -10,13 +10,13 @@ describe("flow 提示词优化", () => {
- -
- -
2. **** 2. ****:20
- -
- -
- -
- -
- -
- 线 -
3. **** 30 3. **** 30
- 使 - 使

View File

@ -18,7 +18,15 @@ import {
Sparkles, Sparkles,
Settings, Settings,
} from "lucide-react"; } from "lucide-react";
import { Dropdown, Modal, Tooltip, Upload, Spin, Popconfirm } from "antd"; import {
Dropdown,
Modal,
Tooltip,
Upload,
Spin,
Popconfirm,
Image,
} from "antd";
import { UploadOutlined } from "@ant-design/icons"; import { UploadOutlined } from "@ant-design/icons";
import { StoryTemplateEntity } from "@/app/service/domain/Entities"; import { StoryTemplateEntity } from "@/app/service/domain/Entities";
import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService"; import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService";
@ -53,9 +61,12 @@ const RenderTemplateStoryMode = ({
setActiveRoleIndex, setActiveRoleIndex,
setActiveRoleImage, setActiveRoleImage,
setActiveRoleAudio, setActiveRoleAudio,
clearData clearData,
} = useTemplateStoryServiceHook(); } = useTemplateStoryServiceHook();
// 使用上传文件hook
const { uploadFile, isUploading } = useUploadFile();
// 本地加载状态,用于 UI 反馈 // 本地加载状态,用于 UI 反馈
const [localLoading, setLocalLoading] = useState(0); const [localLoading, setLocalLoading] = useState(0);
@ -103,14 +114,23 @@ const RenderTemplateStoryMode = ({
} }
}; };
// 处理角色图片上传 // 处理角色图片上传 - 已移至customRequest中处理
const handleRoleImageUpload = (roleIndex: number, file: any) => { // const handleRoleImageUpload = async (roleIndex: number, file: File) => {
if (file && selectedTemplate) { // if (!file || !selectedTemplate) return;
// 模拟上传成功设置图片URL //
const imageUrl = URL.createObjectURL(file); // try {
setActiveRoleImage(imageUrl); // // 使用真正的文件上传功能
} // const imageUrl = await uploadFile(file, (progress) => {
}; // console.log(`上传进度: ${progress}%`);
// });
//
// // 上传成功后,更新角色图片
// setActiveRoleImage(imageUrl);
// } catch (error) {
// console.error("图片上传失败:", error);
// // 这里可以添加错误提示
// }
// };
// 删除角色图片 // 删除角色图片
const handleDeleteRoleImage = (roleIndex: number) => { const handleDeleteRoleImage = (roleIndex: number) => {
@ -122,7 +142,6 @@ const RenderTemplateStoryMode = ({
const templateListRender = () => { const templateListRender = () => {
return ( return (
<div className="w-1/3 p-4 border-r border-white/[0.1]"> <div className="w-1/3 p-4 border-r border-white/[0.1]">
<h3 className="text-xl font-bold text-white mb-6">Story Templates</h3>
<div className="space-y-4 max-h-[700px] overflow-y-auto pr-3 template-list-scroll"> <div className="space-y-4 max-h-[700px] overflow-y-auto pr-3 template-list-scroll">
{templateStoryList.map((template, index) => ( {templateStoryList.map((template, index) => (
<div <div
@ -148,7 +167,7 @@ const RenderTemplateStoryMode = ({
}; };
// 故事编辑器渲染 // 故事编辑器渲染
const storyEditorRender = () => { const storyEditorRender = () => {
return selectedTemplate ? ( return selectedTemplate ? (
<div className="relative h-full"> <div className="relative h-full">
{/* 模板信息头部 - 增加顶部空间 */} {/* 模板信息头部 - 增加顶部空间 */}
<div className="flex gap-3 py-4 border-b border-white/[0.1] h-[300px]"> <div className="flex gap-3 py-4 border-b border-white/[0.1] h-[300px]">
@ -211,25 +230,67 @@ const RenderTemplateStoryMode = ({
listType="picture-card" listType="picture-card"
className="avatar-uploader [&_.ant-upload-select]:!w-32 [&_.ant-upload-select]:!h-32" className="avatar-uploader [&_.ant-upload-select]:!w-32 [&_.ant-upload-select]:!h-32"
showUploadList={false} showUploadList={false}
action="https://660d2bd96ddfa2943b33731c.mockapi.io/api/upload" beforeUpload={(file) => {
beforeUpload={() => false} // 验证文件类型
onChange={(info) => { const isImage = file.type.startsWith("image/");
if (info.file.status === "done") { if (!isImage) {
handleRoleImageUpload( console.error("只能上传图片文件");
activeRoleIndex, return false;
info.file.originFileObj }
// 验证文件大小 (5MB)
const isLt5M = file.size / 1024 / 1024 < 10;
if (!isLt5M) {
console.error("图片大小不能超过10MB");
return false;
}
return true; // 允许文件通过验证
}}
customRequest={async ({ file, onSuccess, onError }) => {
try {
const fileObj = file as File;
console.log(
"开始上传图片文件:",
fileObj.name,
fileObj.type,
fileObj.size
); );
// 使用 hook 上传文件到七牛云
const uploadedUrl = await uploadFile(
fileObj,
(progress) => {
console.log(`上传进度: ${progress}%`);
}
);
console.log("图片上传成功URL:", uploadedUrl);
// 上传成功后,更新角色图片
setActiveRoleImage(uploadedUrl);
// 调用成功回调
onSuccess?.(uploadedUrl);
} catch (error) {
console.error("图片上传失败:", error);
onError?.(error as Error);
} }
}} }}
> >
{activeRole?.photo_url ? ( {activeRole?.photo_url ? (
<div className="relative w-32 h-32 rounded-lg overflow-hidden"> <div className="relative w-32 h-32 rounded-lg overflow-hidden">
<img <Image
src={activeRole.photo_url} src={activeRole.photo_url}
alt="Character Portrait" alt="Character Portrait"
className="w-full h-full object-cover" className="w-full h-full object-cover"
preview={{
mask: null,
maskClassName: "hidden",
}}
fallback="/assets/empty_video.png"
/> />
<button {/* <button
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handleDeleteRoleImage(activeRoleIndex); handleDeleteRoleImage(activeRoleIndex);
@ -238,7 +299,7 @@ const RenderTemplateStoryMode = ({
title="Delete Photo" title="Delete Photo"
> >
<Trash2 className="w-2.5 h-2.5" /> <Trash2 className="w-2.5 h-2.5" />
</button> </button> */}
<div className="absolute inset-0 bg-black/50 opacity-0 hover:opacity-100 transition-opacity duration-200 flex items-center justify-center"> <div className="absolute inset-0 bg-black/50 opacity-0 hover:opacity-100 transition-opacity duration-200 flex items-center justify-center">
<div className="text-white text-center"> <div className="text-white text-center">
<UploadOutlined className="w-4 h-4 mb-1" /> <UploadOutlined className="w-4 h-4 mb-1" />
@ -248,8 +309,17 @@ const RenderTemplateStoryMode = ({
</div> </div>
) : ( ) : (
<div className="w-32 h-32 flex flex-col items-center justify-center text-white/50 bg-white/[0.05] border border-white/[0.1] rounded-lg hover:bg-white/[0.08] transition-colors"> <div className="w-32 h-32 flex flex-col items-center justify-center text-white/50 bg-white/[0.05] border border-white/[0.1] rounded-lg hover:bg-white/[0.08] transition-colors">
<UploadOutlined className="w-6 h-6 mb-1" /> {isUploading ? (
<span className="text-xs">Upload Photo</span> <>
<Loader2 className="w-6 h-6 mb-1 animate-spin" />
<span className="text-xs">...</span>
</>
) : (
<>
<UploadOutlined className="w-6 h-6 mb-1" />
<span className="text-xs">Upload Photo</span>
</>
)}
</div> </div>
)} )}
</Upload> </Upload>
@ -280,11 +350,7 @@ const RenderTemplateStoryMode = ({
Characters Characters
</h4> </h4>
{selectedTemplate.storyRole.map((role, index: number) => ( {selectedTemplate.storyRole.map((role, index: number) => (
<Tooltip <Tooltip key={index} title={role.role_name} placement="left">
key={index}
title={role.role_name}
placement="left"
>
<button <button
data-alt={`character-thumbnail-${index}`} data-alt={`character-thumbnail-${index}`}
className={`w-full aspect-square rounded-lg overflow-hidden border-2 transition-all duration-200 hover:scale-105 ${ className={`w-full aspect-square rounded-lg overflow-hidden border-2 transition-all duration-200 hover:scale-105 ${
@ -294,10 +360,15 @@ const RenderTemplateStoryMode = ({
}`} }`}
onClick={() => setActiveRoleIndex(index)} onClick={() => setActiveRoleIndex(index)}
> >
<img <Image
src={role.photo_url} src={role.photo_url}
alt={role.role_name} alt={role.role_name}
className="w-full h-full object-cover" className="w-full h-full object-cover"
preview={{
mask: null,
maskClassName: "hidden",
}}
fallback="/assets/empty_video.png"
/> />
</button> </button>
</Tooltip> </Tooltip>
@ -305,7 +376,7 @@ const RenderTemplateStoryMode = ({
</div> </div>
</div> </div>
</div> </div>
<div className=" absolute bottom-0 right-0"> <div className=" absolute -bottom-4 right-0">
<ActionButton <ActionButton
isCreating={localLoading > 0} isCreating={localLoading > 0}
handleCreateVideo={handleConfirm} handleCreateVideo={handleConfirm}
@ -321,7 +392,7 @@ const RenderTemplateStoryMode = ({
<p className="text-sm">Please try again later</p> <p className="text-sm">Please try again later</p>
</div> </div>
</div> </div>
) );
}; };
return ( return (
<> <>
@ -329,7 +400,7 @@ const RenderTemplateStoryMode = ({
open={isOpen} open={isOpen}
onCancel={() => { onCancel={() => {
// 清空所有选中的内容数据 // 清空所有选中的内容数据
clearData() clearData();
onClose(); onClose();
}} }}
footer={null} footer={null}
@ -344,7 +415,7 @@ const RenderTemplateStoryMode = ({
</div> </div>
} }
> >
<div className="rounded-2xl"> <div className="rounded-2xl min-h-min transition-all duration-700 ease-out">
{/* 弹窗头部 */} {/* 弹窗头部 */}
<div className="flex gap-4 p-4 border-b border-white/[0.1]"> <div className="flex gap-4 p-4 border-b border-white/[0.1]">
<h2 className="text-2xl font-bold text-white"> <h2 className="text-2xl font-bold text-white">
@ -352,7 +423,7 @@ const RenderTemplateStoryMode = ({
</h2> </h2>
</div> </div>
<GlobalLoad show={isLoading} progress={0}> <GlobalLoad show={isLoading} progress={0}>
<div className="flex gap-4"> <div className="flex gap-4 pb-4 ">
{templateListRender()} {templateListRender()}
<div className="flex-1">{storyEditorRender()}</div> <div className="flex-1">{storyEditorRender()}</div>
</div> </div>
@ -871,22 +942,22 @@ const PhotoStoryModal = ({
<div className="flex items-start gap-4"> <div className="flex items-start gap-4">
{/* 左侧:图片上传 */} {/* 左侧:图片上传 */}
<div className="flex-shrink-0"> <div className="flex-shrink-0">
<div <div
data-alt="image-upload-area" data-alt="image-upload-area"
className={`w-24 h-24 rounded-lg flex flex-col items-center justify-center transition-all duration-300 cursor-pointer ${ className={`w-32 h-32 rounded-lg flex flex-col items-center justify-center transition-all duration-300 cursor-pointer ${
activeImageUrl activeImageUrl
? "border-2 border-white/20 bg-white/[0.05]" ? "border-2 border-white/20 bg-white/[0.05]"
: "border-2 border-dashed border-white/20 bg-white/[0.02] hover:border-white/40 hover:bg-white/[0.05] hover:scale-105" : "border-2 border-dashed border-white/20 bg-white/[0.02] hover:border-white/40 hover:bg-white/[0.05] hover:scale-105"
}`} }`}
onClick={handleImageUpload} onClick={handleImageUpload}
> >
{activeImageUrl ? ( {activeImageUrl ? (
<div className="relative w-full h-full"> <div className="relative w-full h-full">
<img <img
src={activeImageUrl} src={activeImageUrl}
alt="Story inspiration" alt="Story inspiration"
className="w-full h-full object-cover rounded-lg" className="w-full h-full object-cover rounded-lg bg-white/[0.05]"
/> />
<Popconfirm <Popconfirm
title="Clear all content" title="Clear all content"
description="Are you sure you want to clear all content? This action cannot be undone." description="Are you sure you want to clear all content? This action cannot be undone."
@ -932,17 +1003,17 @@ const PhotoStoryModal = ({
key={`${avatar.name}-${index}`} key={`${avatar.name}-${index}`}
className="flex flex-col items-center" className="flex flex-col items-center"
> >
<div className="relative w-14 h-14 rounded-sm overflow-hidden bg-white/[0.05] border border-white/[0.1] mb-2 group cursor-pointer"> <div className="relative w-20 h-20 rounded-sm overflow-hidden bg-white/[0.05] border border-white/[0.1] mb-2 group cursor-pointer">
<img <img
src={avatar.url} src={avatar.url}
alt={avatar.name} alt={avatar.name}
className="w-full h-full object-cover" className="w-full h-full object-cover bg-white/[0.05]"
onError={(e) => { onError={(e) => {
// 如果裁剪的头像加载失败,回退到原图 // 如果裁剪的头像加载失败,回退到原图
const target = e.target as HTMLImageElement; const target = e.target as HTMLImageElement;
target.src = activeImageUrl; target.src = activeImageUrl;
}} }}
/> />
{/* 删除角色按钮 - 使用Tooltip并调整z-index避免被遮挡 */} {/* 删除角色按钮 - 使用Tooltip并调整z-index避免被遮挡 */}
<Tooltip <Tooltip
title="Remove this character from the movie" title="Remove this character from the movie"