From be289b72b3b0ff7890c37dfc89fdf2973f3e89a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E5=BE=B7=E8=BE=89?= Date: Fri, 27 Jun 2025 17:12:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/App.tsx | 3 +- src/api/index.ts | 14 +- src/api/models/BatchVideoGenerateRequest.ts | 9 - ..._image_api_background_custom_image_post.ts | 8 - ...ge_bg_api_v2_local_batch_change_bg_post.ts | 8 +- ...ges_api_v2_local_batch_edit_images_post.ts | 20 ++ ...age_api_local_batch_generate_image_post.ts | 12 - ..._local_batch_generate_image_latest_post.ts | 13 - ...m_edit_image_api_sync_custom_image_post.ts | 8 - src/api/models/VideoGenerateRequest.ts | 10 - src/api/models/index.ts | 7 +- src/api/schemas/$BatchVideoGenerateRequest.ts | 15 -- ..._image_api_background_custom_image_post.ts | 13 - ...ge_bg_api_v2_local_batch_change_bg_post.ts | 9 +- ...es_api_v2_local_batch_edit_images_post.ts} | 12 +- ..._local_batch_generate_image_latest_post.ts | 36 --- ...m_edit_image_api_sync_custom_image_post.ts | 13 - src/api/schemas/$VideoGenerateRequest.ts | 19 -- src/api/services/DefaultService.ts | 150 +++-------- src/api/services/Service.ts | 66 ----- src/api/services/WebhookService.ts | 27 +- src/components/ui/card.tsx | 92 +++++++ .../components/CascaderMultiSelect.tsx | 131 ++++++++++ .../TryOnPage/components/ClothingCard.tsx | 116 +++++++++ src/pages/TryOnPage/index.tsx | 241 ++++++++++++++++++ 25 files changed, 655 insertions(+), 397 deletions(-) delete mode 100644 src/api/models/BatchVideoGenerateRequest.ts delete mode 100644 src/api/models/Body_background_custom_edit_image_api_background_custom_image_post.ts create mode 100644 src/api/models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts delete mode 100644 src/api/models/Body_local_sync_generate_image_api_local_batch_generate_image_post.ts delete mode 100644 src/api/models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts delete mode 100644 src/api/models/Body_sync_custom_edit_image_api_sync_custom_image_post.ts delete mode 100644 src/api/models/VideoGenerateRequest.ts delete mode 100644 src/api/schemas/$BatchVideoGenerateRequest.ts delete mode 100644 src/api/schemas/$Body_background_custom_edit_image_api_background_custom_image_post.ts rename src/api/schemas/{$Body_local_sync_generate_image_api_local_batch_generate_image_post.ts => $Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts} (59%) delete mode 100644 src/api/schemas/$Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts delete mode 100644 src/api/schemas/$Body_sync_custom_edit_image_api_sync_custom_image_post.ts delete mode 100644 src/api/schemas/$VideoGenerateRequest.ts create mode 100644 src/components/ui/card.tsx create mode 100644 src/pages/TryOnPage/components/CascaderMultiSelect.tsx create mode 100644 src/pages/TryOnPage/components/ClothingCard.tsx create mode 100644 src/pages/TryOnPage/index.tsx diff --git a/src/App.tsx b/src/App.tsx index 71ec34a..6628c7c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3,6 +3,7 @@ import { Sidebar, SidebarContent, SidebarMenu, SidebarMenuButton, SidebarMenuIte import { Home, Users } from 'lucide-react'; import { Link, Route, Routes, useLocation } from 'react-router-dom'; import ModelPage from './pages/ModelPage'; +import TryOnPage from './pages/TryOnPage'; const menu = [ { path: '/', label: '首页', icon: }, @@ -33,7 +34,7 @@ function App() {
- 首页内容} /> + } /> } />
diff --git a/src/api/index.ts b/src/api/index.ts index 9881aa2..a8e995b 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -8,19 +8,15 @@ export { OpenAPI } from './core/OpenAPI'; export type { OpenAPIConfig } from './core/OpenAPI'; export type { BatchImageEditData } from './models/BatchImageEditData'; -export type { BatchVideoGenerateRequest } from './models/BatchVideoGenerateRequest'; export type { BatchVideoTaskRequest } from './models/BatchVideoTaskRequest'; export type { Body_async_custom_edit_image_api_async_custom_image_post } from './models/Body_async_custom_edit_image_api_async_custom_image_post'; -export type { Body_background_custom_edit_image_api_background_custom_image_post } from './models/Body_background_custom_edit_image_api_background_custom_image_post'; export type { Body_create_model_api_models_create_post } from './models/Body_create_model_api_models_create_post'; export type { Body_handler_submit_task_api_comfy_async_submit_task_post } from './models/Body_handler_submit_task_api_comfy_async_submit_task_post'; export type { Body_local_async_batch_bg_opt_api_local_batch_change_bg_post } from './models/Body_local_async_batch_bg_opt_api_local_batch_change_bg_post'; export type { Body_local_async_change_bg_api_local_change_bg_post } from './models/Body_local_async_change_bg_api_local_change_bg_post'; export type { Body_local_async_change_bg_api_v2_local_batch_change_bg_post } from './models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post'; +export type { Body_local_async_gen_images_api_v2_local_batch_edit_images_post } from './models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post'; export type { Body_local_async_gen_images_api_v2_local_batch_images_post } from './models/Body_local_async_gen_images_api_v2_local_batch_images_post'; -export type { Body_local_sync_generate_image_api_local_batch_generate_image_post } from './models/Body_local_sync_generate_image_api_local_batch_generate_image_post'; -export type { Body_opt_local_generate_image_api_local_batch_generate_image_latest_post } from './models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post'; -export type { Body_sync_custom_edit_image_api_sync_custom_image_post } from './models/Body_sync_custom_edit_image_api_sync_custom_image_post'; export type { Body_update_model_api_models__model_id__put } from './models/Body_update_model_api_models__model_id__put'; export type { Body_upload_image_api_upload_post } from './models/Body_upload_image_api_upload_post'; export type { HTTPValidationError } from './models/HTTPValidationError'; @@ -28,24 +24,19 @@ export type { ImageEditItem } from './models/ImageEditItem'; export type { TaskQueryRequest } from './models/TaskQueryRequest'; export type { UploadResponse } from './models/UploadResponse'; export type { ValidationError } from './models/ValidationError'; -export type { VideoGenerateRequest } from './models/VideoGenerateRequest'; export type { VideoTaskRequest } from './models/VideoTaskRequest'; export type { VideoTaskStatus } from './models/VideoTaskStatus'; export { $BatchImageEditData } from './schemas/$BatchImageEditData'; -export { $BatchVideoGenerateRequest } from './schemas/$BatchVideoGenerateRequest'; export { $BatchVideoTaskRequest } from './schemas/$BatchVideoTaskRequest'; export { $Body_async_custom_edit_image_api_async_custom_image_post } from './schemas/$Body_async_custom_edit_image_api_async_custom_image_post'; -export { $Body_background_custom_edit_image_api_background_custom_image_post } from './schemas/$Body_background_custom_edit_image_api_background_custom_image_post'; export { $Body_create_model_api_models_create_post } from './schemas/$Body_create_model_api_models_create_post'; export { $Body_handler_submit_task_api_comfy_async_submit_task_post } from './schemas/$Body_handler_submit_task_api_comfy_async_submit_task_post'; export { $Body_local_async_batch_bg_opt_api_local_batch_change_bg_post } from './schemas/$Body_local_async_batch_bg_opt_api_local_batch_change_bg_post'; export { $Body_local_async_change_bg_api_local_change_bg_post } from './schemas/$Body_local_async_change_bg_api_local_change_bg_post'; export { $Body_local_async_change_bg_api_v2_local_batch_change_bg_post } from './schemas/$Body_local_async_change_bg_api_v2_local_batch_change_bg_post'; +export { $Body_local_async_gen_images_api_v2_local_batch_edit_images_post } from './schemas/$Body_local_async_gen_images_api_v2_local_batch_edit_images_post'; export { $Body_local_async_gen_images_api_v2_local_batch_images_post } from './schemas/$Body_local_async_gen_images_api_v2_local_batch_images_post'; -export { $Body_local_sync_generate_image_api_local_batch_generate_image_post } from './schemas/$Body_local_sync_generate_image_api_local_batch_generate_image_post'; -export { $Body_opt_local_generate_image_api_local_batch_generate_image_latest_post } from './schemas/$Body_opt_local_generate_image_api_local_batch_generate_image_latest_post'; -export { $Body_sync_custom_edit_image_api_sync_custom_image_post } from './schemas/$Body_sync_custom_edit_image_api_sync_custom_image_post'; export { $Body_update_model_api_models__model_id__put } from './schemas/$Body_update_model_api_models__model_id__put'; export { $Body_upload_image_api_upload_post } from './schemas/$Body_upload_image_api_upload_post'; export { $HTTPValidationError } from './schemas/$HTTPValidationError'; @@ -53,7 +44,6 @@ export { $ImageEditItem } from './schemas/$ImageEditItem'; export { $TaskQueryRequest } from './schemas/$TaskQueryRequest'; export { $UploadResponse } from './schemas/$UploadResponse'; export { $ValidationError } from './schemas/$ValidationError'; -export { $VideoGenerateRequest } from './schemas/$VideoGenerateRequest'; export { $VideoTaskRequest } from './schemas/$VideoTaskRequest'; export { $VideoTaskStatus } from './schemas/$VideoTaskStatus'; diff --git a/src/api/models/BatchVideoGenerateRequest.ts b/src/api/models/BatchVideoGenerateRequest.ts deleted file mode 100644 index 1ffb972..0000000 --- a/src/api/models/BatchVideoGenerateRequest.ts +++ /dev/null @@ -1,9 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -import type { VideoGenerateRequest } from './VideoGenerateRequest'; -export type BatchVideoGenerateRequest = { - data: Array; -}; - diff --git a/src/api/models/Body_background_custom_edit_image_api_background_custom_image_post.ts b/src/api/models/Body_background_custom_edit_image_api_background_custom_image_post.ts deleted file mode 100644 index c505aa4..0000000 --- a/src/api/models/Body_background_custom_edit_image_api_background_custom_image_post.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type Body_background_custom_edit_image_api_background_custom_image_post = { - img_path: Blob; -}; - diff --git a/src/api/models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts b/src/api/models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts index 760a25e..db607e9 100644 --- a/src/api/models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts +++ b/src/api/models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts @@ -5,12 +5,8 @@ export type Body_local_async_change_bg_api_v2_local_batch_change_bg_post = { clothing_images: Array; /** - * 风格标签 + * 场景标签集合JSON字符串 */ - style: string; - /** - * 场景标签,支持多个标签,标签之间使用逗号分割 - */ - scenes: string; + scenes_tags: string; }; diff --git a/src/api/models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts b/src/api/models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts new file mode 100644 index 0000000..2ba0e3d --- /dev/null +++ b/src/api/models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts @@ -0,0 +1,20 @@ +/* generated using openapi-typescript-codegen -- do no edit */ +/* istanbul ignore file */ +/* tslint:disable */ +/* eslint-disable */ +export type Body_local_async_gen_images_api_v2_local_batch_edit_images_post = { + clothing_images: Array; + /** + * 标签列表JSON字符串,格式:["男_上衣_长款_牛仔_红", "xxxx"] + */ + tag_list: string; + /** + * 场景标签JSON字符串 + */ + scenes_list: string; + /** + * 操作模式,支持 both, edit_only, bg_only + */ + mode?: string; +}; + diff --git a/src/api/models/Body_local_sync_generate_image_api_local_batch_generate_image_post.ts b/src/api/models/Body_local_sync_generate_image_api_local_batch_generate_image_post.ts deleted file mode 100644 index 3602aff..0000000 --- a/src/api/models/Body_local_sync_generate_image_api_local_batch_generate_image_post.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type Body_local_sync_generate_image_api_local_batch_generate_image_post = { - clothing_images: Array; - model_names: string; - model_category: string; - mode?: string; - clothing_dec_prompt?: string; -}; - diff --git a/src/api/models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts b/src/api/models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts deleted file mode 100644 index 3787d4d..0000000 --- a/src/api/models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type Body_opt_local_generate_image_api_local_batch_generate_image_latest_post = { - clothing_images: Array; - model_url: string; - mode?: string; - model_category: string; - clothing_dec_prompt?: string; - scenario_categories?: Array; -}; - diff --git a/src/api/models/Body_sync_custom_edit_image_api_sync_custom_image_post.ts b/src/api/models/Body_sync_custom_edit_image_api_sync_custom_image_post.ts deleted file mode 100644 index fd9c3fc..0000000 --- a/src/api/models/Body_sync_custom_edit_image_api_sync_custom_image_post.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type Body_sync_custom_edit_image_api_sync_custom_image_post = { - img_path: Blob; -}; - diff --git a/src/api/models/VideoGenerateRequest.ts b/src/api/models/VideoGenerateRequest.ts deleted file mode 100644 index 505785e..0000000 --- a/src/api/models/VideoGenerateRequest.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export type VideoGenerateRequest = { - img_url: string; - prompt: string; - duration?: string; -}; - diff --git a/src/api/models/index.ts b/src/api/models/index.ts index 2ce3bff..454c020 100644 --- a/src/api/models/index.ts +++ b/src/api/models/index.ts @@ -1,17 +1,13 @@ export * from './BatchImageEditData'; -export * from './BatchVideoGenerateRequest'; export * from './BatchVideoTaskRequest'; export * from './Body_async_custom_edit_image_api_async_custom_image_post'; -export * from './Body_background_custom_edit_image_api_background_custom_image_post'; export * from './Body_create_model_api_models_create_post'; export * from './Body_handler_submit_task_api_comfy_async_submit_task_post'; export * from './Body_local_async_batch_bg_opt_api_local_batch_change_bg_post'; export * from './Body_local_async_change_bg_api_local_change_bg_post'; export * from './Body_local_async_change_bg_api_v2_local_batch_change_bg_post'; +export * from './Body_local_async_gen_images_api_v2_local_batch_edit_images_post'; export * from './Body_local_async_gen_images_api_v2_local_batch_images_post'; -export * from './Body_local_sync_generate_image_api_local_batch_generate_image_post'; -export * from './Body_opt_local_generate_image_api_local_batch_generate_image_latest_post'; -export * from './Body_sync_custom_edit_image_api_sync_custom_image_post'; export * from './Body_update_model_api_models__model_id__put'; export * from './Body_upload_image_api_upload_post'; export * from './HTTPValidationError'; @@ -19,6 +15,5 @@ export * from './ImageEditItem'; export * from './TaskQueryRequest'; export * from './UploadResponse'; export * from './ValidationError'; -export * from './VideoGenerateRequest'; export * from './VideoTaskRequest'; export * from './VideoTaskStatus'; \ No newline at end of file diff --git a/src/api/schemas/$BatchVideoGenerateRequest.ts b/src/api/schemas/$BatchVideoGenerateRequest.ts deleted file mode 100644 index f2089d6..0000000 --- a/src/api/schemas/$BatchVideoGenerateRequest.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export const $BatchVideoGenerateRequest = { - properties: { - data: { - type: 'array', - contains: { - type: 'VideoGenerateRequest', - }, - isRequired: true, - }, - }, -} as const; diff --git a/src/api/schemas/$Body_background_custom_edit_image_api_background_custom_image_post.ts b/src/api/schemas/$Body_background_custom_edit_image_api_background_custom_image_post.ts deleted file mode 100644 index 2a67489..0000000 --- a/src/api/schemas/$Body_background_custom_edit_image_api_background_custom_image_post.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export const $Body_background_custom_edit_image_api_background_custom_image_post = { - properties: { - img_path: { - type: 'binary', - isRequired: true, - format: 'binary', - }, - }, -} as const; diff --git a/src/api/schemas/$Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts b/src/api/schemas/$Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts index bd0c8cb..267bbcb 100644 --- a/src/api/schemas/$Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts +++ b/src/api/schemas/$Body_local_async_change_bg_api_v2_local_batch_change_bg_post.ts @@ -12,14 +12,9 @@ export const $Body_local_async_change_bg_api_v2_local_batch_change_bg_post = { }, isRequired: true, }, - style: { + scenes_tags: { type: 'string', - description: `风格标签`, - isRequired: true, - }, - scenes: { - type: 'string', - description: `场景标签,支持多个标签,标签之间使用逗号分割`, + description: `场景标签集合JSON字符串`, isRequired: true, }, }, diff --git a/src/api/schemas/$Body_local_sync_generate_image_api_local_batch_generate_image_post.ts b/src/api/schemas/$Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts similarity index 59% rename from src/api/schemas/$Body_local_sync_generate_image_api_local_batch_generate_image_post.ts rename to src/api/schemas/$Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts index a464713..768cca4 100644 --- a/src/api/schemas/$Body_local_sync_generate_image_api_local_batch_generate_image_post.ts +++ b/src/api/schemas/$Body_local_async_gen_images_api_v2_local_batch_edit_images_post.ts @@ -2,7 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -export const $Body_local_sync_generate_image_api_local_batch_generate_image_post = { +export const $Body_local_async_gen_images_api_v2_local_batch_edit_images_post = { properties: { clothing_images: { type: 'array', @@ -12,19 +12,19 @@ export const $Body_local_sync_generate_image_api_local_batch_generate_image_post }, isRequired: true, }, - model_names: { + tag_list: { type: 'string', + description: `标签列表JSON字符串,格式:["男_上衣_长款_牛仔_红", "xxxx"]`, isRequired: true, }, - model_category: { + scenes_list: { type: 'string', + description: `场景标签JSON字符串`, isRequired: true, }, mode: { type: 'string', - }, - clothing_dec_prompt: { - type: 'string', + description: `操作模式,支持 both, edit_only, bg_only`, }, }, } as const; diff --git a/src/api/schemas/$Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts b/src/api/schemas/$Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts deleted file mode 100644 index 99867dd..0000000 --- a/src/api/schemas/$Body_opt_local_generate_image_api_local_batch_generate_image_latest_post.ts +++ /dev/null @@ -1,36 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export const $Body_opt_local_generate_image_api_local_batch_generate_image_latest_post = { - properties: { - clothing_images: { - type: 'array', - contains: { - type: 'binary', - format: 'binary', - }, - isRequired: true, - }, - model_url: { - type: 'string', - isRequired: true, - }, - mode: { - type: 'string', - }, - model_category: { - type: 'string', - isRequired: true, - }, - clothing_dec_prompt: { - type: 'string', - }, - scenario_categories: { - type: 'array', - contains: { - type: 'string', - }, - }, - }, -} as const; diff --git a/src/api/schemas/$Body_sync_custom_edit_image_api_sync_custom_image_post.ts b/src/api/schemas/$Body_sync_custom_edit_image_api_sync_custom_image_post.ts deleted file mode 100644 index 0ca7284..0000000 --- a/src/api/schemas/$Body_sync_custom_edit_image_api_sync_custom_image_post.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export const $Body_sync_custom_edit_image_api_sync_custom_image_post = { - properties: { - img_path: { - type: 'binary', - isRequired: true, - format: 'binary', - }, - }, -} as const; diff --git a/src/api/schemas/$VideoGenerateRequest.ts b/src/api/schemas/$VideoGenerateRequest.ts deleted file mode 100644 index d3becae..0000000 --- a/src/api/schemas/$VideoGenerateRequest.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ -export const $VideoGenerateRequest = { - properties: { - img_url: { - type: 'string', - isRequired: true, - }, - prompt: { - type: 'string', - isRequired: true, - }, - duration: { - type: 'string', - }, - }, -} as const; diff --git a/src/api/services/DefaultService.ts b/src/api/services/DefaultService.ts index a7f7bc5..025a33e 100644 --- a/src/api/services/DefaultService.ts +++ b/src/api/services/DefaultService.ts @@ -3,14 +3,11 @@ /* tslint:disable */ /* eslint-disable */ import type { Body_async_custom_edit_image_api_async_custom_image_post } from '../models/Body_async_custom_edit_image_api_async_custom_image_post'; -import type { Body_background_custom_edit_image_api_background_custom_image_post } from '../models/Body_background_custom_edit_image_api_background_custom_image_post'; import type { Body_local_async_batch_bg_opt_api_local_batch_change_bg_post } from '../models/Body_local_async_batch_bg_opt_api_local_batch_change_bg_post'; import type { Body_local_async_change_bg_api_local_change_bg_post } from '../models/Body_local_async_change_bg_api_local_change_bg_post'; import type { Body_local_async_change_bg_api_v2_local_batch_change_bg_post } from '../models/Body_local_async_change_bg_api_v2_local_batch_change_bg_post'; +import type { Body_local_async_gen_images_api_v2_local_batch_edit_images_post } from '../models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post'; import type { Body_local_async_gen_images_api_v2_local_batch_images_post } from '../models/Body_local_async_gen_images_api_v2_local_batch_images_post'; -import type { Body_local_sync_generate_image_api_local_batch_generate_image_post } from '../models/Body_local_sync_generate_image_api_local_batch_generate_image_post'; -import type { Body_opt_local_generate_image_api_local_batch_generate_image_latest_post } from '../models/Body_opt_local_generate_image_api_local_batch_generate_image_latest_post'; -import type { Body_sync_custom_edit_image_api_sync_custom_image_post } from '../models/Body_sync_custom_edit_image_api_sync_custom_image_post'; import type { Body_upload_image_api_upload_post } from '../models/Body_upload_image_api_upload_post'; import type { TaskQueryRequest } from '../models/TaskQueryRequest'; import type { UploadResponse } from '../models/UploadResponse'; @@ -18,17 +15,6 @@ import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; export class DefaultService { - /** - * Index - * @returns string Successful Response - * @throws ApiError - */ - public static indexGet(): CancelablePromise { - return __request(OpenAPI, { - method: 'GET', - url: '/', - }); - } /** * Upload Image * @returns UploadResponse Successful Response @@ -50,6 +36,7 @@ export class DefaultService { }); } /** + * @deprecated * 本地换背景 * @returns any Successful Response * @throws ApiError @@ -70,6 +57,7 @@ export class DefaultService { }); } /** + * @deprecated * 本地批量换背景图片 * @returns any Successful Response * @throws ApiError @@ -90,26 +78,7 @@ export class DefaultService { }); } /** - * 自定义图片生成 - * @returns any Successful Response - * @throws ApiError - */ - public static syncCustomEditImageApiSyncCustomImagePost({ - formData, - }: { - formData: Body_sync_custom_edit_image_api_sync_custom_image_post, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/sync/custom/image', - formData: formData, - mediaType: 'multipart/form-data', - errors: { - 422: `Validation Error`, - }, - }); - } - /** + * @deprecated * 异步自定义图片生成 - 立即返回task_id * 异步版本:立即返回task_id,避免阻塞worker * 客户端需要用task_id轮询 /api/check_task 查询结果 @@ -132,81 +101,7 @@ export class DefaultService { }); } /** - * 后台任务版本 - 使用BackgroundTasks - * 后台任务版本:立即返回,任务在后台执行 - * 推荐用于不需要立即获取结果的场景 - * @returns any Successful Response - * @throws ApiError - */ - public static backgroundCustomEditImageApiBackgroundCustomImagePost({ - formData, - }: { - formData: Body_background_custom_edit_image_api_background_custom_image_post, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/background/custom/image', - formData: formData, - mediaType: 'multipart/form-data', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * 本地异步生成图片 - 支持多个服装图片批处理 - * @returns any Successful Response - * @throws ApiError - */ - public static localSyncGenerateImageApiLocalBatchGenerateImagePost({ - formData, - }: { - formData: Body_local_sync_generate_image_api_local_batch_generate_image_post, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/local/batch/generate/image', - formData: formData, - mediaType: 'multipart/form-data', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * 新版 异步图片生成接口, 支持多个服装图片处理 - * 新版异步图片生成接口 - 支持多个服装图片文件上传处理 - * - * Args: - * clothing_images: 服装图片文件列表 - * model_url: 模特图片URL - * mode: 处理模式(both/edit_only/bg_only) - * model_category: 模特分类 - * clothing_dec_prompt: 服装描述提示词 - * scenario_categories: 场景分类列表(暂未使用) - * db: 数据库会话 - * - * Returns: - * dict: 异步任务提交结果 - * @returns any Successful Response - * @throws ApiError - */ - public static optLocalGenerateImageApiLocalBatchGenerateImageLatestPost({ - formData, - }: { - formData: Body_opt_local_generate_image_api_local_batch_generate_image_latest_post, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/local/batch/generate/image/latest', - formData: formData, - mediaType: 'multipart/form-data', - errors: { - 422: `Validation Error`, - }, - }); - } - /** + * @deprecated * 本地新版异步图片生成接口 * 本地新版异步图片生成接口 * @@ -238,6 +133,37 @@ export class DefaultService { }, }); } + /** + * 本地新版异步图片生成接口 + * 本地新版异步图片生成接口 + * + * Args: + * clothing_images: 服装图片文件列表 + * tag_list: 标签列表JSON字符串,格式:["男_上衣_长款_牛仔_红", "xxxx"] 注意tag_list 与 clothing_images 长度一致 + * scenes_list: 场景标签JSON字符串,格式:[{"title": "客厅1","prompt": "室内场景..."}] + * mode: 操作模式(both/edit_only/bg_only) + * db: 数据库会话 + * + * Returns: + * dict: 异步任务提交结果 + * @returns any Successful Response + * @throws ApiError + */ + public static localAsyncGenImagesApiV2LocalBatchEditImagesPost({ + formData, + }: { + formData: Body_local_async_gen_images_api_v2_local_batch_edit_images_post, + }): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v2/local/batch/edit/images', + formData: formData, + mediaType: 'multipart/form-data', + errors: { + 422: `Validation Error`, + }, + }); + } /** * 本地新版异步换背景接口 * @returns any Successful Response @@ -263,14 +189,14 @@ export class DefaultService { * @returns any Successful Response * @throws ApiError */ - public static localSyncQueryTaskResultApiLocalBatchQueryTaskResultPost({ + public static localSyncQueryTaskResultApiV2LocalBatchQueryTaskResultPost({ requestBody, }: { requestBody: TaskQueryRequest, }): CancelablePromise { return __request(OpenAPI, { method: 'POST', - url: '/api/local/batch/query/task/result', + url: '/api/v2/local/batch/query/task/result', body: requestBody, mediaType: 'application/json', errors: { diff --git a/src/api/services/Service.ts b/src/api/services/Service.ts index 6475901..05daf27 100644 --- a/src/api/services/Service.ts +++ b/src/api/services/Service.ts @@ -2,11 +2,9 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import type { BatchVideoGenerateRequest } from '../models/BatchVideoGenerateRequest'; import type { BatchVideoTaskRequest } from '../models/BatchVideoTaskRequest'; import type { Body_create_model_api_models_create_post } from '../models/Body_create_model_api_models_create_post'; import type { Body_update_model_api_models__model_id__put } from '../models/Body_update_model_api_models__model_id__put'; -import type { VideoGenerateRequest } from '../models/VideoGenerateRequest'; import type { VideoTaskStatus } from '../models/VideoTaskStatus'; import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; @@ -335,68 +333,4 @@ export class Service { url: '/api/tag/model/tag_list', }); } - /** - * 极梦视频生成任务提交 - * 生成视频API - * @returns any Successful Response - * @throws ApiError - */ - public static generateVideoApiVideoGeneratePost({ - requestBody, - }: { - requestBody: VideoGenerateRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/video/generate', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * 最大支持同时提交5个任务 - * 批量生成视频API - 并发处理,最多同时5个任务 - * @returns any Successful Response - * @throws ApiError - */ - public static batchGenerateVideoApiBatchVideoGeneratePost({ - requestBody, - }: { - requestBody: BatchVideoGenerateRequest, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/batch/video/generate', - body: requestBody, - mediaType: 'application/json', - errors: { - 422: `Validation Error`, - }, - }); - } - /** - * 极梦视频生成进度查询 - * 查询视频生成状态API - * @returns any Successful Response - * @throws ApiError - */ - public static queryVideoStatusApiVideoQueryTaskIdGet({ - taskId, - }: { - taskId: string, - }): CancelablePromise { - return __request(OpenAPI, { - method: 'GET', - url: '/api/video/query/{task_id}', - path: { - 'task_id': taskId, - }, - errors: { - 422: `Validation Error`, - }, - }); - } } diff --git a/src/api/services/WebhookService.ts b/src/api/services/WebhookService.ts index b12740f..b56ba90 100644 --- a/src/api/services/WebhookService.ts +++ b/src/api/services/WebhookService.ts @@ -6,38 +6,15 @@ import type { CancelablePromise } from '../core/CancelablePromise'; import { OpenAPI } from '../core/OpenAPI'; import { request as __request } from '../core/request'; export class WebhookService { - /** - * 同步数据处理 - * @returns any Successful Response - * @throws ApiError - */ - public static webhookHandlerApiHandlerWebhookPost(): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/handler/webhook', - }); - } - /** - * 异步数据处理 - * 异步Webhook处理接口 - 快速响应,后台处理 - * @returns any Successful Response - * @throws ApiError - */ - public static asyncWebhookHandlerApiAsyncHandlerWebhookPost(): CancelablePromise { - return __request(OpenAPI, { - method: 'POST', - url: '/api/async/handler/webhook', - }); - } /** * 异步数据处理 * @returns any Successful Response * @throws ApiError */ - public static asyncWebhookSlotApiAsyncWebhookReciverPost(): CancelablePromise { + public static asyncWebhookSlotApiAsyncWebhookReceiverPost(): CancelablePromise { return __request(OpenAPI, { method: 'POST', - url: '/api/async/webhook/reciver', + url: '/api/async/webhook/receiver', }); } } diff --git a/src/components/ui/card.tsx b/src/components/ui/card.tsx new file mode 100644 index 0000000..d05bbc6 --- /dev/null +++ b/src/components/ui/card.tsx @@ -0,0 +1,92 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Card({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardTitle({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardDescription({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardAction({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardContent({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +function CardFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ) +} + +export { + Card, + CardHeader, + CardFooter, + CardTitle, + CardAction, + CardDescription, + CardContent, +} diff --git a/src/pages/TryOnPage/components/CascaderMultiSelect.tsx b/src/pages/TryOnPage/components/CascaderMultiSelect.tsx new file mode 100644 index 0000000..4e0beb3 --- /dev/null +++ b/src/pages/TryOnPage/components/CascaderMultiSelect.tsx @@ -0,0 +1,131 @@ +import React, { useState } from 'react'; + +interface CascaderNode { + title: string; + children?: CascaderNode[]; + prompt?: string; +} + +interface CascaderMultiSelectProps { + options: CascaderNode[]; + value: string[][]; // 每个已选项为路径数组,如 ['户外', '公园', '公园1'] + onChange: (value: string[][]) => void; +} + +const getLeafPaths = (tree: CascaderNode[], prefix: string[] = []): string[][] => { + let result: string[][] = []; + for (const node of tree) { + const path = [...prefix, node.title]; + if (node.children && node.children.length > 0) { + result = result.concat(getLeafPaths(node.children, path)); + } else { + result.push(path); + } + } + return result; +}; + +const CascaderMultiSelect: React.FC = ({ options, value, onChange }) => { + const [open, setOpen] = useState(false); + const [activePath, setActivePath] = useState([]); + + // 当前级的 options + const getCurrentOptions = () => { + let nodes = options; + for (const t of activePath) { + const node = nodes.find(n => n.title === t); + if (!node || !node.children) return []; + nodes = node.children; + } + return nodes; + }; + + // 判断某路径是否已选 + const isSelected = (path: string[]) => value.some(v => v.join('/') === path.join('/')); + + // 选中叶子节点 + const handleSelect = (path: string[]) => { + if (!isSelected(path)) { + onChange([...value, path]); + } else { + onChange(value.filter(v => v.join('/') !== path.join('/'))); + } + }; + + // 删除 tag + const handleRemove = (path: string[]) => { + onChange(value.filter(v => v.join('/') !== path.join('/'))); + }; + + // 渲染 tag + const renderTags = () => ( +
+ {value.map(v => ( + + {v.join(' / ')} + + + ))} +
+ ); + + // 渲染级联下拉 + const renderCascader = () => { + const currentOptions = getCurrentOptions(); + return ( +
+ {activePath.length > 0 && ( +
+ {activePath.map((t, i) => ( + setActivePath(activePath.slice(0, i + 1))}> + {t} + + ))} +
+ )} +
    + {currentOptions.map(opt => ( +
  • + {opt.children && opt.children.length > 0 ? ( + <> + setActivePath([...activePath, opt.title])}> + {opt.title} + + + ) : ( + + )} +
  • + ))} +
+
+ ); + }; + + return ( +
+
+ {renderTags()} + +
+ {open && renderCascader()} + {open &&
setOpen(false)} />} +
+ ); +}; + +export default CascaderMultiSelect; diff --git a/src/pages/TryOnPage/components/ClothingCard.tsx b/src/pages/TryOnPage/components/ClothingCard.tsx new file mode 100644 index 0000000..2a412f8 --- /dev/null +++ b/src/pages/TryOnPage/components/ClothingCard.tsx @@ -0,0 +1,116 @@ +import React from 'react'; +import { Button } from '@/components/ui/button'; +import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@/components/ui/select'; +import { Card, CardHeader, CardAction, CardContent } from '@/components/ui/card'; +import { X } from 'lucide-react'; +import CascaderMultiSelect from './CascaderMultiSelect'; + +interface Tag { + sex: string; + category: string; + size: string; + material: string; + color: string; +} + +interface TagOptions { + sexOptions: any[]; + categoryOptions: any[]; + sizeOptions: any[]; + materialOptions: any[]; + colorOptions: any[]; +} + +interface ClothingCardProps { + imageUrl: string; + tag: Tag; + options: TagOptions; + idx: number; + onTagChange: (level: keyof Tag, value: string) => void; + onRemove: () => void; + errors?: Partial>; + scenesOptions?: any[]; + scenes?: string[][]; + onScenesChange?: (scenes: string[][]) => void; + fileName?: string; +} + +const LABELS = ['性别', '类别', '尺寸', '材质', '颜色']; +const LEVELS: (keyof Tag)[] = ['sex', 'category', 'size', 'material', 'color']; + +const ClothingCard: React.FC = ({ + imageUrl, + tag, + options, + onTagChange, + onRemove, + errors = {}, + scenesOptions = [], + scenes = [], + onScenesChange, + fileName, +}) => { + return ( + + + + + + + +
+ 预览 + {fileName &&
{fileName}
} +
+
+ {LEVELS.map((level, lidx) => { + let selectOptions: any[] = []; + if (level === 'sex') selectOptions = options.sexOptions; + else if (level === 'category') selectOptions = options.categoryOptions; + else if (level === 'size') selectOptions = options.sizeOptions; + else if (level === 'material') selectOptions = options.materialOptions; + else if (level === 'color') selectOptions = options.colorOptions; + return ( +
+ +
+ + {errors[level] &&
{errors[level]}
} +
+
+ ); + })} + {/* 场景级联多选 */} +
+ +
+ {})} /> +
+
+
+
+
+ ); +}; + +export default ClothingCard; diff --git a/src/pages/TryOnPage/index.tsx b/src/pages/TryOnPage/index.tsx new file mode 100644 index 0000000..735aaf8 --- /dev/null +++ b/src/pages/TryOnPage/index.tsx @@ -0,0 +1,241 @@ +import type { Body_local_async_gen_images_api_v2_local_batch_edit_images_post } from '@/api/models/Body_local_async_gen_images_api_v2_local_batch_edit_images_post'; +import { Button } from '@/components/ui/button'; +import { Form } from '@/components/ui/form'; +import { api } from '@/lib/api'; +import { zodResolver } from '@hookform/resolvers/zod'; +import React, { useEffect, useRef, useState } from 'react'; +import { useForm } from 'react-hook-form'; +import { z } from 'zod'; +import ClothingCard from './components/ClothingCard'; + +// 五级联动的 tag schema +const tagSchema = z.object({ + sex: z.string().min(1, '请选择性别'), + category: z.string().min(1, '请选择类别'), + size: z.string().min(1, '请选择尺寸'), + material: z.string().min(1, '请选择材质'), + color: z.string().min(1, '请选择颜色'), + scenes: z.array(z.array(z.string())).optional(), +}); + +const formSchema = z.object({ + clothing_images: z.array(z.instanceof(File)).min(1, '请上传至少一张服装图片').max(5, '最多上传5个商品'), + tags: z.array(tagSchema), + changeBg: z.boolean().optional(), +}); + +interface TagForm { + sex: string; + category: string; + size: string; + material: string; + color: string; + scenes?: string[][]; +} + +interface FormValues { + clothing_images: File[]; + tags: TagForm[]; + changeBg?: boolean; +} + +const defaultValues: FormValues = { + clothing_images: [], + tags: [], + changeBg: false, +}; + +const TryOnPage: React.FC = () => { + const [tagOptions, setTagOptions] = useState([]); + const [scenesOptions, setScenesOptions] = useState([]); + const [loading, setLoading] = useState(false); + const [result, setResult] = useState(null); + const fileInputRef = useRef(null); + const [imagePreviews, setImagePreviews] = useState([]); + + // 表单 + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues, + }); + + // 拉取标签数据 + useEffect(() => { + api.Service.fetchModelTagsApiTagModelTagListGet().then(data => setTagOptions(data.data || [])); + api.Service.fetchStyleAvailableTagsApiTagStyleTagListGet().then(data => setScenesOptions(data.data || [])); + }, []); + + const tags = form.watch('tags'); + + // 图片上传和标签组同步(append 新卡片) + const handleImageChange = (e: React.ChangeEvent) => { + const files = Array.from(e.target.files || []); + if (!files.length) return; + const oldFiles = form.getValues('clothing_images'); + if (oldFiles.length + files.length > 5) { + alert('最多只能上传5个商品'); + if (fileInputRef.current) fileInputRef.current.value = ''; + return; + } + // 追加到已有图片和标签 + const oldTags = form.getValues('tags'); + const newFiles = [...oldFiles, ...files]; + const newTags = [...oldTags, ...files.map(() => ({ sex: '', category: '', size: '', material: '', color: '', scenes: [] as string[][] }))]; + form.setValue('clothing_images', newFiles); + setImagePreviews(newFiles.map(file => URL.createObjectURL(file))); + form.setValue('tags', newTags); + // 清空 input 以便连续选择同一图片 + if (fileInputRef.current) fileInputRef.current.value = ''; + }; + + // 删除图片及对应标签组 + const handleRemoveImage = (idx: number) => { + const files = form.getValues('clothing_images'); + const tags = form.getValues('tags'); + const newFiles = files.filter((_, i) => i !== idx); + const newTags = tags.filter((_, i) => i !== idx); + form.setValue('clothing_images', newFiles); + setImagePreviews(newFiles.map(file => URL.createObjectURL(file))); + form.setValue('tags', newTags); + }; + + // 级联联动清空下级 + const handleCascade = (idx: number, level: keyof TagForm, value: string) => { + const newTags = [...form.getValues('tags')]; + if (level === 'sex') { + newTags[idx] = { sex: value, category: '', size: '', material: '', color: '', scenes: newTags[idx]?.scenes || [] }; + } else if (level === 'category') { + newTags[idx] = { ...newTags[idx], category: value, size: '', material: '', color: '', scenes: newTags[idx]?.scenes || [] }; + } else if (level === 'size') { + newTags[idx] = { ...newTags[idx], size: value, material: '', color: '', scenes: newTags[idx]?.scenes || [] }; + } else if (level === 'material') { + newTags[idx] = { ...newTags[idx], material: value, scenes: newTags[idx]?.scenes || [] }; + } else if (level === 'color') { + newTags[idx] = { ...newTags[idx], color: value, scenes: newTags[idx]?.scenes || [] }; + } + form.setValue('tags', newTags); + }; + + // 场景多选 + const handleScenesChange = (idx: number, scenes: string[][]) => { + const newTags = [...form.getValues('tags')]; + newTags[idx] = { ...newTags[idx], scenes }; + form.setValue('tags', newTags); + }; + + // 计算每个卡片的options + const getTagOptions = (idx: number) => { + const tag = tags[idx] || {}; + // 性别 + const sexOptions = tagOptions; + // 类别 + const categoryOptions = tag.sex ? tagOptions.find((t: any) => t.title === tag.sex)?.children || [] : []; + // 尺寸 + const sizeOptions = tag.category ? categoryOptions.find((t: any) => t.title === tag.category)?.children || [] : []; + // 材质 + const materialOptions = tag.size + ? sizeOptions.find((t: any) => t.title === tag.size)?.children?.find((c: any) => c.title === '材质')?.children || [] + : []; + // 颜色 + const colorOptions = tag.size + ? sizeOptions.find((t: any) => t.title === tag.size)?.children?.find((c: any) => c.title === '颜色')?.children || [] + : []; + return { sexOptions, categoryOptions, sizeOptions, materialOptions, colorOptions }; + }; + + // 递归查找 prompt + function findPromptByPath(tree: any[], path: string[]): string { + let node: any = null; + let nodes: any[] = tree; + for (const t of path) { + node = nodes.find((n: any) => n.title === t); + if (!node) return ''; + nodes = node.children || []; + } + return node && node.prompt ? node.prompt : ''; + } + + // 提交 + const onSubmit = async (values: FormValues) => { + setLoading(true); + setResult(null); + const results: any[] = []; + try { + for (let i = 0; i < values.clothing_images.length; i++) { + const tag = values.tags[i]; + const scenesArr: string[][] = tag.scenes || []; + const scenes_list = scenesArr.map((path: string[]) => ({ + title: path.join('/'), + prompt: findPromptByPath(scenesOptions, path), + })); + const formData: Body_local_async_gen_images_api_v2_local_batch_edit_images_post = { + clothing_images: [values.clothing_images[i]], + tag_list: JSON.stringify([[tag.sex, tag.category, tag.size, tag.material, tag.color].join('_')]), + scenes_list: JSON.stringify(scenes_list.map(s => ({ title: s.title, prompt: s.prompt }))), + mode: 'both', + }; + // eslint-disable-next-line no-await-in-loop + const res = await api.DefaultService.localAsyncGenImagesApiV2LocalBatchEditImagesPost({ formData }); + results.push(res); + } + setResult(results); + } catch (e: any) { + setResult({ error: e?.message || '请求失败' }); + } finally { + setLoading(false); + } + }; + + const clothing_images = form.watch('clothing_images'); + + return ( +
+

换装体验

+
+ + {/* 卡片式图片+表单 */} +
+ {clothing_images && + clothing_images.length > 0 && + clothing_images.map((_, idx) => { + const tag: TagForm = tags[idx] || { sex: '', category: '', size: '', material: '', color: '', scenes: [] }; + const { sexOptions, categoryOptions, sizeOptions, materialOptions, colorOptions } = getTagOptions(idx); + const fileName = clothing_images[idx]?.name; + return ( + handleCascade(idx, level, value)} + onRemove={() => handleRemoveImage(idx)} + scenesOptions={scenesOptions} + scenes={tag.scenes || []} + onScenesChange={scenes => handleScenesChange(idx, scenes)} + fileName={fileName} + /> + ); + })} + + +
+ +
+ + {/* 结果展示 */} + {result && ( +
+

结果

+
{JSON.stringify(result, null, 2)}
+
+ )} +
+ ); +}; + +export default TryOnPage;