|
|
|
@ -1,8 +1,9 @@ |
|
|
|
import { memo, useCallback, useEffect, useMemo, useRef, useState, type ChangeEvent } from "react"; |
|
|
|
import { Dropdown, Input } from "@arco-design/web-react"; |
|
|
|
import { Dropdown, Message } from "@arco-design/web-react"; |
|
|
|
import { useTranslation } from "react-i18next"; |
|
|
|
import { nanoid } from "nanoid"; |
|
|
|
import { getTemplateVideoMaterialList } from "../../../api/api"; |
|
|
|
import { uploadComposerImage } from "../composerCommon"; |
|
|
|
import "./ActionMimicUploadPromptSection.scss"; |
|
|
|
|
|
|
|
export type ComposerMediaType = "image" | "video" | "audio"; |
|
|
|
@ -103,6 +104,7 @@ export function ActionMimicUploadPromptSection({ |
|
|
|
const actionMimicUploadInputRef = useRef<HTMLInputElement>(null); |
|
|
|
const [exampleDropdownOpen, setExampleDropdownOpen] = useState(false); |
|
|
|
const [exampleLoading, setExampleLoading] = useState(false); |
|
|
|
const [exampleUploadLoading, setExampleUploadLoading] = useState(false); |
|
|
|
const [exampleList, setExampleList] = useState<ActionMimicMaterialItem[]>([]); |
|
|
|
const [selectedExampleItem, setSelectedExampleItem] = useState<ActionMimicSelectedItem | null>(null); |
|
|
|
const [customUploadExample, setCustomUploadExample] = useState<{ |
|
|
|
@ -135,7 +137,7 @@ export function ActionMimicUploadPromptSection({ |
|
|
|
useEffect(() => { |
|
|
|
// 组件卸载时释放临时上传示例的 object URL,避免内存泄漏。
|
|
|
|
return () => { |
|
|
|
if (customUploadExample?.url) { |
|
|
|
if (customUploadExample?.url?.startsWith("blob:")) { |
|
|
|
URL.revokeObjectURL(customUploadExample.url); |
|
|
|
} |
|
|
|
}; |
|
|
|
@ -219,31 +221,28 @@ export function ActionMimicUploadPromptSection({ |
|
|
|
const file = evt.target.files?.[0]; |
|
|
|
evt.target.value = ""; |
|
|
|
if (!file || !file.type.startsWith("video/")) return; |
|
|
|
const duration = await resolveVideoDuration(file); |
|
|
|
const videoUrl = URL.createObjectURL(file); |
|
|
|
setExampleUploadLoading(true); |
|
|
|
try { |
|
|
|
const [duration, remoteUrl] = await Promise.all([resolveVideoDuration(file), uploadComposerImage(file)]); |
|
|
|
const uploadId = nanoid(); |
|
|
|
const formattedDuration = `00:${String(duration).padStart(2, "0")}`; |
|
|
|
setCustomUploadExample((prev) => { |
|
|
|
if (prev?.url) { |
|
|
|
URL.revokeObjectURL(prev.url); |
|
|
|
} |
|
|
|
return { |
|
|
|
const uploadedItem = { |
|
|
|
id: uploadId, |
|
|
|
name: file.name ?? null, |
|
|
|
url: videoUrl, |
|
|
|
url: remoteUrl, |
|
|
|
duration, |
|
|
|
displayDuration: formattedDuration, |
|
|
|
type: "用户上传素材", |
|
|
|
type: "用户上传素材" as const, |
|
|
|
}; |
|
|
|
}); |
|
|
|
setSelectedExampleItem({ |
|
|
|
id: uploadId, |
|
|
|
name: file.name ?? null, |
|
|
|
url: videoUrl, |
|
|
|
duration, |
|
|
|
displayDuration: formattedDuration, |
|
|
|
type: "用户上传素材", |
|
|
|
}); |
|
|
|
setCustomUploadExample(uploadedItem); |
|
|
|
setSelectedExampleItem(uploadedItem); |
|
|
|
} catch { |
|
|
|
Message.error(t("composer.uploadFailed")); |
|
|
|
} finally { |
|
|
|
if (isMountedRef.current) { |
|
|
|
setExampleUploadLoading(false); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
const onExampleItemClick = useCallback((item: ActionMimicSelectedItem) => { |
|
|
|
setSelectedExampleItem(item); |
|
|
|
@ -265,7 +264,12 @@ export function ActionMimicUploadPromptSection({ |
|
|
|
<p className="layoutShell__actionMimicDropdownTitle"> |
|
|
|
{t("composer.actionMimic.exampleTitle", { defaultValue: "查看示例" })} |
|
|
|
</p> |
|
|
|
<button type="button" className="layoutShell__actionMimicDropdownUploadBtn" onClick={openActionMimicUploadPicker}> |
|
|
|
<button |
|
|
|
type="button" |
|
|
|
className="layoutShell__actionMimicDropdownUploadBtn" |
|
|
|
onClick={openActionMimicUploadPicker} |
|
|
|
disabled={exampleUploadLoading} |
|
|
|
> |
|
|
|
{t("composer.actionMimic.upload", { defaultValue: "上传" })} |
|
|
|
</button> |
|
|
|
</div> |
|
|
|
|