refactor: 简化穿搭图片生成弹框,移除风格偏好和生成记录功能
- 移除OutfitImageGenerator中的风格偏好标签功能 - 删除stylePreferences状态和相关函数 - 移除风格偏好UI界面和预设按钮 - 更新使用说明,去掉风格偏好描述 - 简化OutfitImageGenerationModal组件 - 移除穿搭图片生成记录显示功能 - 删除OutfitImageGallery组件使用 - 移除底部操作栏和记录相关参数 - 改为单列居中布局,专注生成功能 - 清理ModelDetail页面中不再使用的代码 - 移除outfitRecordsLoading状态 - 删除handleDeleteOutfitRecord函数 - 简化loadOutfitRecords函数 - 优化用户体验,界面更加简洁清爽
This commit is contained in:
parent
26353f49a7
commit
44486e5df7
|
|
@ -2,20 +2,15 @@ import React, { useEffect } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { X, Sparkles } from 'lucide-react';
|
import { X, Sparkles } from 'lucide-react';
|
||||||
import { Model } from '../types/model';
|
import { Model } from '../types/model';
|
||||||
import { OutfitImageRecord, OutfitImageGenerationRequest } from '../types/outfitImage';
|
import { OutfitImageGenerationRequest } from '../types/outfitImage';
|
||||||
import { OutfitImageGenerator } from './OutfitImageGenerator';
|
import { OutfitImageGenerator } from './OutfitImageGenerator';
|
||||||
import { OutfitImageGallery } from './OutfitImageGallery';
|
|
||||||
|
|
||||||
interface OutfitImageGenerationModalProps {
|
interface OutfitImageGenerationModalProps {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
model: Model;
|
model: Model;
|
||||||
outfitRecords: OutfitImageRecord[];
|
|
||||||
onGenerate: (request: OutfitImageGenerationRequest) => Promise<void>;
|
onGenerate: (request: OutfitImageGenerationRequest) => Promise<void>;
|
||||||
onDeleteRecord: (record: OutfitImageRecord) => Promise<void>;
|
|
||||||
onRefreshRecords: () => Promise<void>;
|
|
||||||
isGenerating?: boolean;
|
isGenerating?: boolean;
|
||||||
recordsLoading?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -26,12 +21,8 @@ export const OutfitImageGenerationModal: React.FC<OutfitImageGenerationModalProp
|
||||||
isOpen,
|
isOpen,
|
||||||
onClose,
|
onClose,
|
||||||
model,
|
model,
|
||||||
outfitRecords,
|
|
||||||
onGenerate,
|
onGenerate,
|
||||||
onDeleteRecord,
|
isGenerating = false
|
||||||
onRefreshRecords,
|
|
||||||
isGenerating = false,
|
|
||||||
recordsLoading = false
|
|
||||||
}) => {
|
}) => {
|
||||||
// 键盘事件处理
|
// 键盘事件处理
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -93,50 +84,18 @@ export const OutfitImageGenerationModal: React.FC<OutfitImageGenerationModalProp
|
||||||
|
|
||||||
{/* 主要内容区域 */}
|
{/* 主要内容区域 */}
|
||||||
<div className="flex-1 overflow-y-auto p-6">
|
<div className="flex-1 overflow-y-auto p-6">
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6 h-full">
|
<div className="max-w-2xl mx-auto">
|
||||||
{/* 穿搭图片生成器 */}
|
{/* 穿搭图片生成器 */}
|
||||||
<div className="space-y-6">
|
<OutfitImageGenerator
|
||||||
<OutfitImageGenerator
|
modelId={model.id}
|
||||||
modelId={model.id}
|
modelPhotos={model.photos}
|
||||||
modelPhotos={model.photos}
|
onGenerate={onGenerate}
|
||||||
onGenerate={onGenerate}
|
isGenerating={isGenerating}
|
||||||
isGenerating={isGenerating}
|
/>
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* 穿搭图片生成记录 */}
|
|
||||||
<div className="space-y-6">
|
|
||||||
<OutfitImageGallery
|
|
||||||
records={outfitRecords}
|
|
||||||
onDelete={onDeleteRecord}
|
|
||||||
onRefresh={onRefreshRecords}
|
|
||||||
loading={recordsLoading}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 底部操作栏(可选) */}
|
|
||||||
<div className="flex items-center justify-between p-6 border-t border-gray-200 bg-gray-50">
|
|
||||||
<div className="text-sm text-gray-500">
|
|
||||||
共 {outfitRecords.length} 条生成记录
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex items-center space-x-3">
|
|
||||||
<button
|
|
||||||
onClick={onRefreshRecords}
|
|
||||||
className="px-4 py-2 text-gray-600 hover:text-gray-800 hover:bg-gray-200 rounded-lg transition-colors text-sm"
|
|
||||||
>
|
|
||||||
刷新记录
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={onClose}
|
|
||||||
className="px-6 py-2 bg-gray-600 text-white rounded-lg hover:bg-gray-700 transition-colors text-sm"
|
|
||||||
>
|
|
||||||
关闭
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>,
|
</div>,
|
||||||
modalRoot
|
modalRoot
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,7 @@ import {
|
||||||
AlertCircle,
|
AlertCircle,
|
||||||
Image as ImageIcon,
|
Image as ImageIcon,
|
||||||
Wand2,
|
Wand2,
|
||||||
Settings,
|
Settings
|
||||||
Plus
|
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import { ModelPhoto, PhotoType } from '../types/model';
|
import { ModelPhoto, PhotoType } from '../types/model';
|
||||||
import { OutfitImageGenerationRequest } from '../types/outfitImage';
|
import { OutfitImageGenerationRequest } from '../types/outfitImage';
|
||||||
|
|
@ -38,7 +37,6 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
const [selectedModelImageId, setSelectedModelImageId] = useState<string>('');
|
const [selectedModelImageId, setSelectedModelImageId] = useState<string>('');
|
||||||
const [productImages, setProductImages] = useState<string[]>([]);
|
const [productImages, setProductImages] = useState<string[]>([]);
|
||||||
const [generationPrompt, setGenerationPrompt] = useState('');
|
const [generationPrompt, setGenerationPrompt] = useState('');
|
||||||
const [stylePreferences, setStylePreferences] = useState<string[]>([]);
|
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [dragOver, setDragOver] = useState(false);
|
const [dragOver, setDragOver] = useState(false);
|
||||||
|
|
||||||
|
|
@ -125,17 +123,7 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
setProductImages(prev => prev.filter((_, i) => i !== index));
|
setProductImages(prev => prev.filter((_, i) => i !== index));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 添加风格偏好
|
|
||||||
const addStylePreference = useCallback((style: string) => {
|
|
||||||
if (style.trim() && !stylePreferences.includes(style.trim())) {
|
|
||||||
setStylePreferences(prev => [...prev, style.trim()]);
|
|
||||||
}
|
|
||||||
}, [stylePreferences]);
|
|
||||||
|
|
||||||
// 移除风格偏好
|
|
||||||
const removeStylePreference = useCallback((index: number) => {
|
|
||||||
setStylePreferences(prev => prev.filter((_, i) => i !== index));
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// 处理生成请求
|
// 处理生成请求
|
||||||
const handleGenerate = useCallback(async () => {
|
const handleGenerate = useCallback(async () => {
|
||||||
|
|
@ -157,7 +145,7 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
model_image_id: selectedModelImageId,
|
model_image_id: selectedModelImageId,
|
||||||
product_image_paths: productImages,
|
product_image_paths: productImages,
|
||||||
generation_prompt: generationPrompt || undefined,
|
generation_prompt: generationPrompt || undefined,
|
||||||
style_preferences: stylePreferences.length > 0 ? stylePreferences : undefined
|
style_preferences: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
await onGenerate(request);
|
await onGenerate(request);
|
||||||
|
|
@ -166,12 +154,11 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
setSelectedModelImageId('');
|
setSelectedModelImageId('');
|
||||||
setProductImages([]);
|
setProductImages([]);
|
||||||
setGenerationPrompt('');
|
setGenerationPrompt('');
|
||||||
setStylePreferences([]);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('生成穿搭图片失败:', error);
|
console.error('生成穿搭图片失败:', error);
|
||||||
setError(`生成穿搭图片失败: ${error}`);
|
setError(`生成穿搭图片失败: ${error}`);
|
||||||
}
|
}
|
||||||
}, [modelId, selectedModelImageId, productImages, generationPrompt, stylePreferences, onGenerate]);
|
}, [modelId, selectedModelImageId, productImages, generationPrompt, onGenerate]);
|
||||||
|
|
||||||
const canGenerate = selectedModelImageId && productImages.length > 0 && !isGenerating && !disabled;
|
const canGenerate = selectedModelImageId && productImages.length > 0 && !isGenerating && !disabled;
|
||||||
|
|
||||||
|
|
@ -323,43 +310,7 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 风格偏好 */}
|
|
||||||
<div>
|
|
||||||
<label className="block text-sm font-medium text-gray-700 mb-2">
|
|
||||||
风格偏好标签
|
|
||||||
</label>
|
|
||||||
<div className="flex flex-wrap gap-2 mb-2">
|
|
||||||
{stylePreferences.map((style, index) => (
|
|
||||||
<span
|
|
||||||
key={index}
|
|
||||||
className="inline-flex items-center px-3 py-1 bg-purple-100 text-purple-800 text-sm rounded-full"
|
|
||||||
>
|
|
||||||
{style}
|
|
||||||
<button
|
|
||||||
onClick={() => removeStylePreference(index)}
|
|
||||||
className="ml-2 text-purple-600 hover:text-purple-800"
|
|
||||||
disabled={disabled || isGenerating}
|
|
||||||
>
|
|
||||||
<X className="w-3 h-3" />
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex space-x-2">
|
|
||||||
{['时尚', '休闲', '商务', '运动', '甜美', '酷炫'].map((style) => (
|
|
||||||
<button
|
|
||||||
key={style}
|
|
||||||
onClick={() => addStylePreference(style)}
|
|
||||||
className="px-3 py-1 text-sm border border-gray-300 rounded-full hover:bg-gray-50 transition-colors"
|
|
||||||
disabled={disabled || isGenerating || stylePreferences.includes(style)}
|
|
||||||
>
|
|
||||||
<Plus className="w-3 h-3 inline mr-1" />
|
|
||||||
{style}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 错误提示 */}
|
{/* 错误提示 */}
|
||||||
|
|
@ -410,7 +361,7 @@ export const OutfitImageGenerator: React.FC<OutfitImageGeneratorProps> = ({
|
||||||
<ul className="space-y-1 text-xs">
|
<ul className="space-y-1 text-xs">
|
||||||
<li>• 选择一张模特的个人形象照片作为基础</li>
|
<li>• 选择一张模特的个人形象照片作为基础</li>
|
||||||
<li>• 上传要搭配的商品图片(服装、配饰等)</li>
|
<li>• 上传要搭配的商品图片(服装、配饰等)</li>
|
||||||
<li>• 可选择添加生成提示词和风格偏好</li>
|
<li>• 可选择添加生成提示词来指导AI生成</li>
|
||||||
<li>• 点击生成按钮,AI将为您创建穿搭效果图</li>
|
<li>• 点击生成按钮,AI将为您创建穿搭效果图</li>
|
||||||
<li>• 生成的图片数量与上传的商品图片数量相等</li>
|
<li>• 生成的图片数量与上传的商品图片数量相等</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,7 @@ const ModelDetail: React.FC = () => {
|
||||||
const [dashboardStats, setDashboardStats] = useState<ModelDashboardStats | null>(null);
|
const [dashboardStats, setDashboardStats] = useState<ModelDashboardStats | null>(null);
|
||||||
const [statsLoading, setStatsLoading] = useState(false);
|
const [statsLoading, setStatsLoading] = useState(false);
|
||||||
const [outfitRecords, setOutfitRecords] = useState<OutfitImageRecord[]>([]);
|
const [outfitRecords, setOutfitRecords] = useState<OutfitImageRecord[]>([]);
|
||||||
const [outfitRecordsLoading, setOutfitRecordsLoading] = useState(false);
|
|
||||||
const [generatingOutfit, setGeneratingOutfit] = useState(false);
|
const [generatingOutfit, setGeneratingOutfit] = useState(false);
|
||||||
const [activeTab, setActiveTab] = useState<TabId>('overview');
|
const [activeTab, setActiveTab] = useState<TabId>('overview');
|
||||||
const [dynamics] = useState<ModelDynamic[]>([]);
|
const [dynamics] = useState<ModelDynamic[]>([]);
|
||||||
|
|
@ -169,13 +169,10 @@ const ModelDetail: React.FC = () => {
|
||||||
if (!id) return;
|
if (!id) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
setOutfitRecordsLoading(true);
|
|
||||||
const records = await OutfitImageService.getOutfitImageRecords(id);
|
const records = await OutfitImageService.getOutfitImageRecords(id);
|
||||||
setOutfitRecords(records);
|
setOutfitRecords(records);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('加载穿搭图片记录失败:', err);
|
console.error('加载穿搭图片记录失败:', err);
|
||||||
} finally {
|
|
||||||
setOutfitRecordsLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -196,19 +193,7 @@ const ModelDetail: React.FC = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 删除穿搭图片记录
|
|
||||||
const handleDeleteOutfitRecord = async (record: OutfitImageRecord) => {
|
|
||||||
try {
|
|
||||||
await OutfitImageService.deleteOutfitImageRecord(record.id);
|
|
||||||
|
|
||||||
// 重新加载记录和统计信息
|
|
||||||
await loadOutfitRecords();
|
|
||||||
await loadDashboardStats();
|
|
||||||
} catch (err) {
|
|
||||||
console.error('删除穿搭图片记录失败:', err);
|
|
||||||
setError(err as string);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 上传照片
|
// 上传照片
|
||||||
const handleUploadPhotos = async () => {
|
const handleUploadPhotos = async () => {
|
||||||
|
|
@ -563,12 +548,8 @@ const ModelDetail: React.FC = () => {
|
||||||
isOpen={showOutfitModal}
|
isOpen={showOutfitModal}
|
||||||
onClose={() => setShowOutfitModal(false)}
|
onClose={() => setShowOutfitModal(false)}
|
||||||
model={model}
|
model={model}
|
||||||
outfitRecords={outfitRecords}
|
|
||||||
onGenerate={handleGenerateOutfitImages}
|
onGenerate={handleGenerateOutfitImages}
|
||||||
onDeleteRecord={handleDeleteOutfitRecord}
|
|
||||||
onRefreshRecords={loadOutfitRecords}
|
|
||||||
isGenerating={generatingOutfit}
|
isGenerating={generatingOutfit}
|
||||||
recordsLoading={outfitRecordsLoading}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue