fix
This commit is contained in:
parent
d6dd6109c0
commit
c973aaa58c
|
|
@ -53,57 +53,7 @@ class ResourceCategoryManager:
|
||||||
|
|
||||||
def _create_default_categories(self) -> List[ResourceCategory]:
|
def _create_default_categories(self) -> List[ResourceCategory]:
|
||||||
"""创建默认分类"""
|
"""创建默认分类"""
|
||||||
now = datetime.now().isoformat()
|
default_categories = []
|
||||||
default_categories = [
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="人物视频",
|
|
||||||
ai_prompt="包含人物、人脸、人体的视频素材",
|
|
||||||
color="#FF6B6B",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
),
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="风景视频",
|
|
||||||
ai_prompt="自然风景、城市景观、建筑物的视频素材",
|
|
||||||
color="#4ECDC4",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
),
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="动物视频",
|
|
||||||
ai_prompt="动物、宠物、野生动物的视频素材",
|
|
||||||
color="#45B7D1",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
),
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="音乐音效",
|
|
||||||
ai_prompt="背景音乐、音效、声音素材",
|
|
||||||
color="#96CEB4",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
),
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="文字图片",
|
|
||||||
ai_prompt="文字、标题、图标、图形素材",
|
|
||||||
color="#FFEAA7",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
),
|
|
||||||
ResourceCategory(
|
|
||||||
id=str(uuid.uuid4()),
|
|
||||||
title="特效素材",
|
|
||||||
ai_prompt="转场、特效、动画、滤镜素材",
|
|
||||||
color="#DDA0DD",
|
|
||||||
created_at=now,
|
|
||||||
updated_at=now
|
|
||||||
)
|
|
||||||
]
|
|
||||||
self._save_categories(default_categories)
|
self._save_categories(default_categories)
|
||||||
return default_categories
|
return default_categories
|
||||||
|
|
||||||
|
|
@ -123,7 +73,7 @@ class ResourceCategoryManager:
|
||||||
|
|
||||||
def get_all_categories(self) -> List[Dict]:
|
def get_all_categories(self) -> List[Dict]:
|
||||||
"""获取所有分类"""
|
"""获取所有分类"""
|
||||||
return [asdict(category) for category in self.categories if category.is_active]
|
return [asdict(category) for category in self.categories]
|
||||||
|
|
||||||
def get_category_by_id(self, category_id: str) -> Optional[Dict]:
|
def get_category_by_id(self, category_id: str) -> Optional[Dict]:
|
||||||
"""根据ID获取分类"""
|
"""根据ID获取分类"""
|
||||||
|
|
@ -192,9 +142,7 @@ class ResourceCategoryManager:
|
||||||
results = []
|
results = []
|
||||||
|
|
||||||
for category in self.categories:
|
for category in self.categories:
|
||||||
if (category.is_active and
|
if (keyword in category.title.lower() or keyword in category.ai_prompt.lower()):
|
||||||
(keyword in category.title.lower() or
|
|
||||||
keyword in category.ai_prompt.lower())):
|
|
||||||
results.append(asdict(category))
|
results.append(asdict(category))
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
|
||||||
|
|
@ -203,70 +203,79 @@ const ProjectManagePage: React.FC = () => {
|
||||||
{/* 项目列表 */}
|
{/* 项目列表 */}
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
{filteredProjects.map((project) => (
|
{filteredProjects.map((project) => (
|
||||||
<div key={project.id} className="bg-white rounded-lg shadow-sm border border-gray-200 p-6">
|
<div key={project.id} className="bg-white rounded-lg shadow-sm border border-gray-200 overflow-hidden">
|
||||||
{/* 项目标题 */}
|
{/* 商品图片 */}
|
||||||
<div className="flex items-center justify-between mb-4">
|
<div className="h-32 bg-gray-100 overflow-hidden">
|
||||||
<h3 className="text-lg font-semibold text-gray-900">{project.name}</h3>
|
{project.product_image ? (
|
||||||
|
<>
|
||||||
<div className="flex items-center space-x-2">
|
<img
|
||||||
<button
|
src={project.product_image.startsWith('http') ? project.product_image : `file://${project.product_image}`}
|
||||||
onClick={() => handleOpenDirectory(project.id)}
|
alt={project.product_name || project.name}
|
||||||
className="p-2 text-gray-400 hover:text-green-600 transition-colors"
|
className="w-full h-full object-cover"
|
||||||
title="打开目录"
|
onError={(e) => {
|
||||||
>
|
const target = e.target as HTMLImageElement
|
||||||
<FolderOpen size={16} />
|
target.style.display = 'none'
|
||||||
</button>
|
const fallback = target.parentElement?.querySelector('.image-fallback') as HTMLElement
|
||||||
<button
|
if (fallback) {
|
||||||
onClick={() => startEdit(project)}
|
fallback.style.display = 'flex'
|
||||||
className="p-2 text-gray-400 hover:text-blue-600 transition-colors"
|
}
|
||||||
title="编辑"
|
}}
|
||||||
>
|
/>
|
||||||
<Edit size={16} />
|
<div className="image-fallback hidden w-full h-full bg-gray-200 flex items-center justify-center">
|
||||||
</button>
|
<Package size={32} className="text-gray-400" />
|
||||||
<button
|
</div>
|
||||||
onClick={() => handleDeleteProject(project.id)}
|
</>
|
||||||
className="p-2 text-gray-400 hover:text-red-600 transition-colors"
|
) : (
|
||||||
title="删除"
|
<div className="w-full h-full bg-gray-200 flex items-center justify-center">
|
||||||
>
|
<Package size={32} className="text-gray-400" />
|
||||||
<Trash2 size={16} />
|
</div>
|
||||||
</button>
|
)}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 项目信息 */}
|
<div className="p-6">
|
||||||
<div className="space-y-3">
|
{/* 项目标题 */}
|
||||||
{/* 本地目录 */}
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div>
|
<h3 className="text-lg font-semibold text-gray-900">{project.name}</h3>
|
||||||
<p className="text-sm text-gray-600">本地目录:</p>
|
|
||||||
<p className="text-sm text-gray-900 truncate" title={project.local_directory}>
|
<div className="flex items-center space-x-2">
|
||||||
{project.local_directory}
|
<button
|
||||||
</p>
|
onClick={() => handleOpenDirectory(project.id)}
|
||||||
|
className="p-2 text-gray-400 hover:text-green-600 transition-colors"
|
||||||
|
title="打开目录"
|
||||||
|
>
|
||||||
|
<FolderOpen size={16} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => startEdit(project)}
|
||||||
|
className="p-2 text-gray-400 hover:text-blue-600 transition-colors"
|
||||||
|
title="编辑"
|
||||||
|
>
|
||||||
|
<Edit size={16} />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={() => handleDeleteProject(project.id)}
|
||||||
|
className="p-2 text-gray-400 hover:text-red-600 transition-colors"
|
||||||
|
title="删除"
|
||||||
|
>
|
||||||
|
<Trash2 size={16} />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 商品信息 */}
|
{/* 项目信息 */}
|
||||||
{project.product_name && (
|
<div className="space-y-3">
|
||||||
<div>
|
{/* 商品信息 */}
|
||||||
<p className="text-sm text-gray-600">商品名:</p>
|
{project.product_name && (
|
||||||
<p className="text-sm text-gray-900">{project.product_name}</p>
|
<div>
|
||||||
</div>
|
<p className="text-sm text-gray-600">商品名:</p>
|
||||||
)}
|
<p className="text-sm text-gray-900">{project.product_name}</p>
|
||||||
|
|
||||||
{/* 商品图片 */}
|
|
||||||
{project.product_image && (
|
|
||||||
<div>
|
|
||||||
<p className="text-sm text-gray-600">商品图片:</p>
|
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
<Package size={16} className="text-gray-400" />
|
|
||||||
<p className="text-sm text-gray-900 truncate flex-1" title={project.product_image}>
|
|
||||||
{project.product_image.split('/').pop()}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
|
||||||
|
|
||||||
{/* 创建时间 */}
|
{/* 创建时间 */}
|
||||||
<div className="text-xs text-gray-400 pt-2 border-t border-gray-100">
|
<div className="text-xs text-gray-400 pt-2 border-t border-gray-100">
|
||||||
创建于 {new Date(project.created_at).toLocaleDateString()}
|
创建于 {new Date(project.created_at).toLocaleDateString()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -391,16 +400,19 @@ const ProjectManagePage: React.FC = () => {
|
||||||
<p className="text-xs text-gray-500 mb-1">预览:</p>
|
<p className="text-xs text-gray-500 mb-1">预览:</p>
|
||||||
<div className="w-20 h-20 border border-gray-200 rounded-lg overflow-hidden bg-gray-50 flex items-center justify-center">
|
<div className="w-20 h-20 border border-gray-200 rounded-lg overflow-hidden bg-gray-50 flex items-center justify-center">
|
||||||
<img
|
<img
|
||||||
src={`file://${formData.product_image}`}
|
src={formData.product_image.startsWith('http') ? formData.product_image : `file://${formData.product_image}`}
|
||||||
alt="商品图片预览"
|
alt="商品图片预览"
|
||||||
className="w-full h-full object-cover"
|
className="w-full h-full object-cover"
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
const target = e.target as HTMLImageElement
|
const target = e.target as HTMLImageElement
|
||||||
target.style.display = 'none'
|
target.style.display = 'none'
|
||||||
target.nextElementSibling!.classList.remove('hidden')
|
const fallback = target.parentElement?.querySelector('.fallback-text') as HTMLElement
|
||||||
|
if (fallback) {
|
||||||
|
fallback.style.display = 'block'
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="hidden text-xs text-gray-400 text-center p-2">
|
<div className="fallback-text hidden text-xs text-gray-400 text-center p-2">
|
||||||
无法预览
|
无法预览
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue