加入视频比例配置

This commit is contained in:
北枳 2025-09-20 16:33:51 +08:00
parent c9f9a0030b
commit 170a8b7a4f
10 changed files with 179 additions and 23 deletions

View File

@ -106,6 +106,8 @@ export interface CreateMovieProjectV2Request {
language: string; language: string;
/** 图片URL */ /** 图片URL */
image_url: string; image_url: string;
/** 画面比例(横/竖屏) */
aspect_ratio?: "16:9" | "9:16";
} }
/** /**
@ -249,6 +251,8 @@ export interface CreateMovieProjectV3Request {
/** 道具照片URL */ /** 道具照片URL */
photo_url: string; photo_url: string;
}[]; }[];
/** 画面比例(横/竖屏) */
aspect_ratio?: "16:9" | "9:16";
} }
/** /**

View File

@ -57,7 +57,8 @@ interface UseImageStoryService {
user_id: string, user_id: string,
mode?: "auto" | "manual", mode?: "auto" | "manual",
resolution?: "720p" | "1080p" | "4k", resolution?: "720p" | "1080p" | "4k",
language?: string language?: string,
aspectRatio?: "16:9" | "9:16"
) => Promise<{ project_id: string } | undefined>; ) => Promise<{ project_id: string } | undefined>;
/** 设置角色分析 */ /** 设置角色分析 */
setCharactersAnalysis: Dispatch<SetStateAction<CharacterAnalysis[]>>; setCharactersAnalysis: Dispatch<SetStateAction<CharacterAnalysis[]>>;
@ -457,7 +458,8 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
user_id: string, user_id: string,
mode: "auto" | "manual" = "auto", mode: "auto" | "manual" = "auto",
resolution: "720p" | "1080p" | "4k" = "720p", resolution: "720p" | "1080p" | "4k" = "720p",
language: string = "English" language: string = "English",
aspectRatio?: "16:9" | "9:16"
) => { ) => {
try { try {
if (hasAnalyzed) { if (hasAnalyzed) {
@ -480,7 +482,8 @@ export const useImageStoryServiceHook = (): UseImageStoryService => {
character_briefs, character_briefs,
language, language,
image_url: activeImageUrl, image_url: activeImageUrl,
project_id:taskId project_id:taskId,
...(aspectRatio ? { aspect_ratio: aspectRatio } : {})
}; };
// 调用create_movie_project_v2接口 // 调用create_movie_project_v2接口

View File

@ -28,7 +28,8 @@ interface UseTemplateStoryService {
user_id: string, user_id: string,
mode: "auto" | "manual", mode: "auto" | "manual",
resolution: "720p" | "1080p" | "4k", resolution: "720p" | "1080p" | "4k",
language: string language: string,
aspectRatio?: "16:9" | "9:16"
) => Promise<string | undefined>; ) => Promise<string | undefined>;
/** 设置选中的模板 */ /** 设置选中的模板 */
setSelectedTemplate: (template: StoryTemplateEntity | null) => void; setSelectedTemplate: (template: StoryTemplateEntity | null) => void;
@ -250,7 +251,8 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => {
user_id: string, user_id: string,
mode: "auto" | "manual" = "auto", mode: "auto" | "manual" = "auto",
resolution: "720p" | "1080p" | "4k" = "720p", resolution: "720p" | "1080p" | "4k" = "720p",
language: string = "English" language: string = "English",
aspectRatio?: "16:9" | "9:16"
) => { ) => {
console.log('selectedTemplate', selectedTemplate) console.log('selectedTemplate', selectedTemplate)
try { try {
@ -271,7 +273,8 @@ export const useTemplateStoryServiceHook = (): UseTemplateStoryService => {
storyItem: selectedTemplate?.storyItem || [], storyItem: selectedTemplate?.storyItem || [],
freeInput: selectedTemplate?.freeInput || [], freeInput: selectedTemplate?.freeInput || [],
language, language,
template_id: selectedTemplate?.template_id || "" template_id: selectedTemplate?.template_id || "",
...(aspectRatio ? { aspect_ratio: aspectRatio } : {})
}; };
console.log("params", params); console.log("params", params);
const result = await MovieProjectService.createProject( const result = await MovieProjectService.createProject(

View File

@ -0,0 +1,86 @@
"use client";
import { Dropdown } from "antd";
import { RectangleHorizontal, RectangleVertical } from "lucide-react";
import { AspectRatioOptions } from "./types";
export type AspectRatioValue =
| "VIDEO_ASPECT_RATIO_LANDSCAPE"
| "VIDEO_ASPECT_RATIO_PORTRAIT";
interface AspectRatioSelectorProps {
/** Current selected aspect ratio value */
value: AspectRatioValue;
/** Change handler when an option is selected */
onChange: (value: AspectRatioValue) => void;
/** Optional className to customize the trigger button */
className?: string;
/** Optional dropdown placement, defaults to top */
placement?: "top" | "bottom" | "topLeft" | "topRight" | "bottomLeft" | "bottomRight";
/** data-alt tag for analytics/testing */
dataAlt?: string;
}
/**
* A reusable aspect ratio selector (landscape/portrait) using Antd Dropdown.
* Shows an icon and label, and calls onChange when a new ratio is chosen.
* @param {AspectRatioValue} value - current selected value
* @param {(v: AspectRatioValue) => void} onChange - change handler
* @param {string} [className] - optional className for trigger button
* @param {string} [placement] - Dropdown placement, default is top
* @param {string} [dataAlt] - data-alt attribute for the trigger
* @returns {JSX.Element}
*/
export const AspectRatioSelector = ({
value,
onChange,
className,
placement = "top",
dataAlt = "config-aspect-ratio",
}: AspectRatioSelectorProps) => {
return (
<Dropdown
overlayClassName="aspect-dropdown"
menu={{
items: AspectRatioOptions.map((option) => ({
key: option.value,
label: (
<div
className={`flex items-center gap-2 px-2 py-2 ${
option.value === value ? "bg-white/[0.12] rounded-md" : ""
}`}
>
{option.value === "VIDEO_ASPECT_RATIO_LANDSCAPE" ? (
<RectangleHorizontal className="w-4 h-4" />
) : (
<RectangleVertical className="w-4 h-4" />
)}
<span className="text-sm text-white">{option.label}</span>
</div>
),
})),
onClick: ({ key }) => onChange(key as AspectRatioValue),
}}
trigger={["click"]}
placement={placement}
>
<button
data-alt={dataAlt}
className={`flex items-center gap-1 text-white/80 transition-all duration-200 px-2 py-2 ${className || ""}`}
>
{value === "VIDEO_ASPECT_RATIO_LANDSCAPE" ? (
<RectangleHorizontal className={"w-4 h-4"} />
) : (
<RectangleVertical className={"w-4 h-4"} />
)}
<span className="text-sm">
{value === "VIDEO_ASPECT_RATIO_LANDSCAPE" ? "16:9" : "9:16"}
</span>
</button>
</Dropdown>
);
};
export default AspectRatioSelector;

View File

@ -50,6 +50,7 @@ import { PcTemplateModal } from "./PcTemplateModal";
import { H5TemplateDrawer } from "./H5TemplateDrawer"; import { H5TemplateDrawer } from "./H5TemplateDrawer";
import { PcPhotoStoryModal } from "./PcPhotoStoryModal"; import { PcPhotoStoryModal } from "./PcPhotoStoryModal";
import { H5PhotoStoryDrawer } from "./H5PhotoStoryDrawer"; import { H5PhotoStoryDrawer } from "./H5PhotoStoryDrawer";
import { AspectRatioSelector } from "./AspectRatioSelector";
const LauguageOptions = [ const LauguageOptions = [
{ value: "english", label: "English", isVip: false, code:'EN' }, { value: "english", label: "English", isVip: false, code:'EN' },
@ -75,6 +76,8 @@ const VideoDurationOptions = [
{ value: "unlimited", label: "unlimited" }, { value: "unlimited", label: "unlimited" },
]; ];
// aspect ratio options moved to reusable component
/**模板故事模式弹窗组件 */ /**模板故事模式弹窗组件 */
/** /**
* *
@ -128,6 +131,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
language: string; language: string;
videoDuration: string; videoDuration: string;
expansion_mode: boolean; expansion_mode: boolean;
aspect_ratio: "VIDEO_ASPECT_RATIO_LANDSCAPE" | "VIDEO_ASPECT_RATIO_PORTRAIT";
}; };
const [configOptions, setConfigOptions] = useState<ConfigOptions>({ const [configOptions, setConfigOptions] = useState<ConfigOptions>({
@ -136,6 +140,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
language: "english", language: "english",
videoDuration: "unlimited", videoDuration: "unlimited",
expansion_mode: true, expansion_mode: true,
aspect_ratio: "VIDEO_ASPECT_RATIO_LANDSCAPE",
}); });
// 从 localStorage 初始化配置 // 从 localStorage 初始化配置
@ -150,6 +155,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
language: parsed.language || "english", language: parsed.language || "english",
videoDuration: parsed.videoDuration || "1min", videoDuration: parsed.videoDuration || "1min",
expansion_mode: typeof parsed.expansion_mode === 'boolean' ? parsed.expansion_mode : false, expansion_mode: typeof parsed.expansion_mode === 'boolean' ? parsed.expansion_mode : false,
aspect_ratio: parsed.aspect_ratio || "VIDEO_ASPECT_RATIO_LANDSCAPE",
}); });
} catch (error) { } catch (error) {
console.warn('解析保存的配置失败,使用默认配置:', error); console.warn('解析保存的配置失败,使用默认配置:', error);
@ -205,6 +211,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
language: configOptions.language, language: configOptions.language,
video_duration: configOptions.videoDuration, video_duration: configOptions.videoDuration,
expansion_mode: configOptions.expansion_mode, expansion_mode: configOptions.expansion_mode,
aspect_ratio: configOptions.aspect_ratio,
}; };
// 调用创建剧集API // 调用创建剧集API
@ -301,7 +308,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
{/* 第二行功能按钮和Action按钮 - 同一行 */} {/* 第二行功能按钮和Action按钮 - 同一行 */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
{/* 左侧功能按钮区域 */} {/* 左侧功能按钮区域 */}
<div className="flex items-center gap-1"> <div className="flex items-center gap-1 flex-wrap sm:flex-nowrap">
{/* {/*
<Tooltip <Tooltip
title="Get creative ideas for your story" title="Get creative ideas for your story"
@ -335,7 +342,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
</Tooltip> </Tooltip>
{/* 分隔线 */} {/* 分隔线 */}
<div className="w-px h-4 bg-white/[0.20]"></div> <div className="hidden sm:block w-px h-4 bg-white/[0.20]"></div>
{/* 图片故事按钮 */} {/* 图片故事按钮 */}
<Tooltip title="Create movie from image" placement="top" trigger={isDesktop ? "hover" : "contextMenu"}> <Tooltip title="Create movie from image" placement="top" trigger={isDesktop ? "hover" : "contextMenu"}>
@ -372,7 +379,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
)} )}
{/* 分隔线 */} {/* 分隔线 */}
<div className="w-px h-4 bg-white/[0.20]"></div> <div className="hidden sm:block w-px h-4 bg-white/[0.20]"></div>
{/* 语言配置 */} {/* 语言配置 */}
<Dropdown <Dropdown
@ -400,7 +407,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
> >
<button <button
data-alt={`config-language`} data-alt={`config-language`}
className={`flex items-center gap-1 text-white/80 transition-all duration-200 px-2 py-2`} className={`flex items-center gap-1 text-white/80 transition-all duration-200 ${isMobile ? 'px-1' : 'px-2'} py-2`}
> >
<Globe className={"w-4 h-4"} /> <Globe className={"w-4 h-4"} />
<span className="text-sm">{LauguageOptions.find((option) => option.value === configOptions.language)?.code}</span> <span className="text-sm">{LauguageOptions.find((option) => option.value === configOptions.language)?.code}</span>
@ -408,7 +415,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
</Dropdown> </Dropdown>
{/* 分隔线 */} {/* 分隔线 */}
<div className="w-px h-4 bg-white/[0.20]"></div> <div className="hidden sm:block w-px h-4 bg-white/[0.20]"></div>
{/* 剧本扩展开关 */} {/* 剧本扩展开关 */}
<Tooltip title="Enable script expansion" placement="top" trigger={isDesktop ? "hover" : "click"}> <Tooltip title="Enable script expansion" placement="top" trigger={isDesktop ? "hover" : "click"}>
@ -422,14 +429,14 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
onChange={(checked) => onConfigChange('expansion_mode', checked)} onChange={(checked) => onConfigChange('expansion_mode', checked)}
/> />
</div> </div>
<span className={`text-xs text-white`}> <span className={`text-xs text-white hidden sm:inline`}>
{configOptions.expansion_mode ? 'On' : 'Off'} {configOptions.expansion_mode ? 'On' : 'Off'}
</span> </span>
</div> </div>
</Tooltip> </Tooltip>
{/* 分隔线 */} {/* 分隔线 */}
<div className="w-px h-4 bg-white/[0.20]"></div> <div className="hidden sm:block w-px h-4 bg-white/[0.20]"></div>
{/* 时长选择 */} {/* 时长选择 */}
<Dropdown <Dropdown
@ -454,12 +461,23 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
> >
<button <button
data-alt={`config-video-duration`} data-alt={`config-video-duration`}
className={`flex items-center gap-1 text-white/80 transition-all duration-200 px-2 py-2`} className={`flex items-center gap-1 text-white/80 transition-all duration-200 ${isMobile ? 'px-1' : 'px-2'} py-2`}
> >
<Clock className={"w-4 h-4"} /> <Clock className={"w-4 h-4"} />
<span className="text-sm">{configOptions.videoDuration}</span> <span className="text-sm">{isMobile ? (configOptions.videoDuration === 'unlimited' ? '∞' : configOptions.videoDuration.replace('min', 'm')) : configOptions.videoDuration}</span>
</button> </button>
</Dropdown> </Dropdown>
{/* 分隔线(移动端隐藏,避免拥挤) */}
<div className="hidden sm:block w-px h-4 bg-white/[0.20]"></div>
{/* 横/竖屏选择 */}
<AspectRatioSelector
value={configOptions.aspect_ratio}
onChange={(v) => onConfigChange('aspect_ratio', v)}
placement="top"
className={`${isMobile ? '!px-1' : ''}`}
/>
</div> </div>
{/* 右侧Action按钮 */} {/* 右侧Action按钮 */}

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Drawer, Popconfirm, Tooltip, Upload } from "antd"; import { Drawer, Popconfirm, Tooltip, Upload, Dropdown } from "antd";
import { ImagePlay, Sparkles, Trash2 } from "lucide-react"; import { ImagePlay, Sparkles, Trash2 } from "lucide-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import GlobalLoad from "../common/GlobalLoad"; import GlobalLoad from "../common/GlobalLoad";
@ -9,6 +9,7 @@ import { ActionButton } from "../common/ActionButton";
import { HighlightEditor } from "../common/HighlightEditor"; import { HighlightEditor } from "../common/HighlightEditor";
import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService"; import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService";
import { useLoadScriptText } from "@/app/service/domain/service"; import { useLoadScriptText } from "@/app/service/domain/service";
import { AspectRatioSelector, AspectRatioValue } from "./AspectRatioSelector";
type ConfigOptions = { type ConfigOptions = {
mode: "auto" | "manual"; mode: "auto" | "manual";
@ -79,6 +80,7 @@ export const H5PhotoStoryDrawer = ({
const { loadingText } = useLoadScriptText(isLoading); const { loadingText } = useLoadScriptText(isLoading);
const [localLoading, setLocalLoading] = useState(0); const [localLoading, setLocalLoading] = useState(0);
const [aspectUI, setAspectUI] = useState<AspectRatioValue>("VIDEO_ASPECT_RATIO_LANDSCAPE");
const router = useRouter(); const router = useRouter();
const taskProgressRef = useRef(taskProgress); const taskProgressRef = useRef(taskProgress);
const [cursorPosition, setCursorPosition] = useState(0); const [cursorPosition, setCursorPosition] = useState(0);
@ -117,7 +119,8 @@ export const H5PhotoStoryDrawer = ({
String(User.id), String(User.id),
configOptions.mode as "auto" | "manual", configOptions.mode as "auto" | "manual",
configOptions.resolution as "720p" | "1080p" | "4k", configOptions.resolution as "720p" | "1080p" | "4k",
configOptions.language configOptions.language,
aspectUI === 'VIDEO_ASPECT_RATIO_LANDSCAPE' ? '16:9' : '9:16'
); );
if (!episodeResponse) return; if (!episodeResponse) return;
const episodeId = episodeResponse.project_id; const episodeId = episodeResponse.project_id;
@ -355,7 +358,13 @@ export const H5PhotoStoryDrawer = ({
</div> </div>
<div data-alt="bottom-action-bar" className="sticky bottom-0 left-0 right-0 backdrop-blur border-t border-white/10 px-3 py-2"> <div data-alt="bottom-action-bar" className="sticky bottom-0 left-0 right-0 backdrop-blur border-t border-white/10 px-3 py-2">
<div className="flex items-center justify-end"> <div className="flex items-center justify-end gap-2">
{/* 横/竖屏选择 */}
<AspectRatioSelector
value={aspectUI}
onChange={setAspectUI}
placement="top"
/>
{!hasAnalyzed ? ( {!hasAnalyzed ? (
<Tooltip title={activeImageUrl ? "Analyze image content" : "Please upload an image first"} placement="top"> <Tooltip title={activeImageUrl ? "Analyze image content" : "Please upload an image first"} placement="top">
<div> <div>

View File

@ -11,6 +11,8 @@ import { useUploadFile } from "@/app/service/domain/service";
import { ActionButton } from "../common/ActionButton"; import { ActionButton } from "../common/ActionButton";
import GlobalLoad from "../common/GlobalLoad"; import GlobalLoad from "../common/GlobalLoad";
import { motion, AnimatePresence } from "framer-motion"; import { motion, AnimatePresence } from "framer-motion";
import { Dropdown } from "antd";
import { AspectRatioSelector, AspectRatioValue } from "./AspectRatioSelector";
interface H5TemplateDrawerProps { interface H5TemplateDrawerProps {
isMobile: boolean; isMobile: boolean;
@ -73,6 +75,7 @@ export const H5TemplateDrawer = ({
const [isDescExpanded, setIsDescExpanded] = useState(false); const [isDescExpanded, setIsDescExpanded] = useState(false);
// 自由输入框布局 // 自由输入框布局
const [freeInputLayout, setFreeInputLayout] = useState('bottom'); const [freeInputLayout, setFreeInputLayout] = useState('bottom');
const [aspectUI, setAspectUI] = useState<AspectRatioValue>("VIDEO_ASPECT_RATIO_LANDSCAPE");
// 自由输入框布局 // 自由输入框布局
useEffect(() => { useEffect(() => {
@ -119,7 +122,8 @@ export const H5TemplateDrawer = ({
String(User.id), String(User.id),
configOptions.mode, configOptions.mode,
configOptions.resolution, configOptions.resolution,
configOptions.language configOptions.language,
aspectUI === 'VIDEO_ASPECT_RATIO_LANDSCAPE' ? '16:9' : '9:16'
); );
if (projectId) { if (projectId) {
@ -552,6 +556,12 @@ export const H5TemplateDrawer = ({
/> />
</div> </div>
)} )}
{/* 横/竖屏选择 */}
<AspectRatioSelector
value={aspectUI}
onChange={setAspectUI}
placement="top"
/>
<ActionButton <ActionButton
isCreating={isTemplateCreating || localLoading > 0} isCreating={isTemplateCreating || localLoading > 0}
handleCreateVideo={handleConfirm} handleCreateVideo={handleConfirm}

View File

@ -1,7 +1,7 @@
"use client"; "use client";
import { useEffect, useRef, useState } from "react"; import { useEffect, useRef, useState } from "react";
import { Modal, Tooltip, Popconfirm, Upload } from "antd"; import { Modal, Tooltip, Popconfirm, Upload, Dropdown } from "antd";
import { ImagePlay, Sparkles, Trash2 } from "lucide-react"; import { ImagePlay, Sparkles, Trash2 } from "lucide-react";
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import GlobalLoad from "../common/GlobalLoad"; import GlobalLoad from "../common/GlobalLoad";
@ -9,6 +9,7 @@ import { ActionButton } from "../common/ActionButton";
import { HighlightEditor } from "../common/HighlightEditor"; import { HighlightEditor } from "../common/HighlightEditor";
import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService"; import { useImageStoryServiceHook } from "@/app/service/Interaction/ImageStoryService";
import { useLoadScriptText } from "@/app/service/domain/service"; import { useLoadScriptText } from "@/app/service/domain/service";
import { AspectRatioSelector, AspectRatioValue } from "./AspectRatioSelector";
type ConfigOptions = { type ConfigOptions = {
mode: "auto" | "manual"; mode: "auto" | "manual";
@ -61,6 +62,7 @@ export const PcPhotoStoryModal = ({
} = useImageStoryServiceHook(); } = useImageStoryServiceHook();
const { loadingText } = useLoadScriptText(isLoading); const { loadingText } = useLoadScriptText(isLoading);
const [localLoading, setLocalLoading] = useState(0); const [localLoading, setLocalLoading] = useState(0);
const [aspectUI, setAspectUI] = useState<AspectRatioValue>("VIDEO_ASPECT_RATIO_LANDSCAPE");
const router = useRouter(); const router = useRouter();
const taskProgressRef = useRef(taskProgress); const taskProgressRef = useRef(taskProgress);
const [cursorPosition, setCursorPosition] = useState(0); const [cursorPosition, setCursorPosition] = useState(0);
@ -103,7 +105,8 @@ export const PcPhotoStoryModal = ({
String(User.id), String(User.id),
configOptions.mode as "auto" | "manual", configOptions.mode as "auto" | "manual",
configOptions.resolution as "720p" | "1080p" | "4k", configOptions.resolution as "720p" | "1080p" | "4k",
configOptions.language configOptions.language,
aspectUI === 'VIDEO_ASPECT_RATIO_LANDSCAPE' ? '16:9' : '9:16'
); );
if (!episodeResponse) return; if (!episodeResponse) return;
const episodeId = episodeResponse.project_id; const episodeId = episodeResponse.project_id;
@ -317,7 +320,13 @@ export const PcPhotoStoryModal = ({
type={"role"} type={"role"}
placeholder="Share your creative ideas about the image and let AI create a movie story for you..." placeholder="Share your creative ideas about the image and let AI create a movie story for you..."
/> />
<div className="absolute bottom-1 right-0 flex gap-2"> <div className="absolute bottom-1 right-0 flex gap-2 items-center">
{/* 横/竖屏选择 */}
<AspectRatioSelector
value={aspectUI}
onChange={setAspectUI}
placement="top"
/>
{!hasAnalyzed ? ( {!hasAnalyzed ? (
<Tooltip title={activeImageUrl ? "Analyze image content" : "Please upload an image first"} placement="top"> <Tooltip title={activeImageUrl ? "Analyze image content" : "Please upload an image first"} placement="top">
<ActionButton <ActionButton

View File

@ -11,6 +11,7 @@ import {
Tooltip, Tooltip,
Upload, Upload,
Image, Image,
Dropdown,
} from "antd"; } 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";
@ -20,6 +21,7 @@ import { useRouter } from "next/navigation";
import { useUploadFile } from "@/app/service/domain/service"; import { useUploadFile } from "@/app/service/domain/service";
import { ActionButton } from "../common/ActionButton"; import { ActionButton } from "../common/ActionButton";
import GlobalLoad from "../common/GlobalLoad"; import GlobalLoad from "../common/GlobalLoad";
import { AspectRatioSelector, AspectRatioValue } from "./AspectRatioSelector";
/** /**
* *
@ -102,6 +104,7 @@ export const PcTemplateModal = ({
// 自由输入框布局 // 自由输入框布局
const [freeInputLayout, setFreeInputLayout] = useState('bottom'); const [freeInputLayout, setFreeInputLayout] = useState('bottom');
const router = useRouter(); const router = useRouter();
const [aspectUI, setAspectUI] = useState<AspectRatioValue>("VIDEO_ASPECT_RATIO_LANDSCAPE");
// 组件挂载时获取模板列表 // 组件挂载时获取模板列表
useEffect(() => { useEffect(() => {
@ -179,7 +182,8 @@ export const PcTemplateModal = ({
String(User.id), String(User.id),
configOptions.mode, configOptions.mode,
configOptions.resolution, configOptions.resolution,
configOptions.language configOptions.language,
aspectUI === 'VIDEO_ASPECT_RATIO_LANDSCAPE' ? '16:9' : '9:16'
); );
if (projectId) { if (projectId) {
@ -703,6 +707,12 @@ export const PcTemplateModal = ({
/> />
</div> </div>
)} )}
{/* 横/竖屏选择 */}
<AspectRatioSelector
value={aspectUI}
onChange={setAspectUI}
placement="top"
/>
<ActionButton <ActionButton
isCreating={isTemplateCreating || localLoading > 0} isCreating={isTemplateCreating || localLoading > 0}
handleCreateVideo={handleConfirm} handleCreateVideo={handleConfirm}

View File

@ -0,0 +1,4 @@
export const AspectRatioOptions = [
{ value: "VIDEO_ASPECT_RATIO_LANDSCAPE", label: "16:9" },
{ value: "VIDEO_ASPECT_RATIO_PORTRAIT", label: "9:16" },
];