From 231b28d0eb544d8c8f24f031d8dfdcb5b05eb5d3 Mon Sep 17 00:00:00 2001 From: root Date: Fri, 11 Jul 2025 15:45:24 +0800 Subject: [PATCH] fix --- docs/MATERIAL_CATEGORY_FILTER_GUIDE.md | 177 ++++++++++++++++ src/components/ProjectMaterialsCenter.tsx | 125 +++++++++++- src/utils/materialCategoryMatcher.ts | 237 ++++++++++++++++++++++ 3 files changed, 534 insertions(+), 5 deletions(-) create mode 100644 docs/MATERIAL_CATEGORY_FILTER_GUIDE.md create mode 100644 src/utils/materialCategoryMatcher.ts diff --git a/docs/MATERIAL_CATEGORY_FILTER_GUIDE.md b/docs/MATERIAL_CATEGORY_FILTER_GUIDE.md new file mode 100644 index 0000000..936ee61 --- /dev/null +++ b/docs/MATERIAL_CATEGORY_FILTER_GUIDE.md @@ -0,0 +1,177 @@ +# 项目详情页面素材分类筛选功能指南 + +## 🎯 功能概述 + +在项目详情页面的素材管理区域,新增了素材分类筛选功能,允许用户根据预设的分类快速筛选和查找项目中的素材。 + +## 🚀 功能特点 + +### 1. 智能分类匹配 +- **标签匹配**: 根据素材的标签自动匹配分类 +- **文件名匹配**: 根据文件名中的关键词匹配分类 +- **AI提示匹配**: 利用分类的AI识别提示进行智能匹配 + +### 2. 实时数量统计 +- **全部分类**: 显示项目中所有素材的总数 +- **具体分类**: 显示每个分类下匹配的素材数量 +- **动态更新**: 素材变化时自动更新统计数据 + +### 3. 视觉化标识 +- **颜色标识**: 每个分类按钮使用对应的分类颜色 +- **选中状态**: 当前选中的分类高亮显示 +- **数量显示**: 分类名称后显示匹配的素材数量 + +## 📍 使用位置 + +在项目详情页面的素材管理中心,筛选器区域包含: +- 使用状态筛选(全部/已使用/未使用) +- 模特标签筛选 +- 类型筛选(全部/原始/分镜) +- **素材分类筛选**(新增功能) + +## 🔧 使用方法 + +### 1. 查看分类列表 +1. 进入任意项目的详情页面 +2. 在素材管理区域找到筛选器 +3. 查看"分类:"标签下的分类按钮列表 + +### 2. 筛选特定分类 +1. 点击任意分类按钮(如"商业 (5)") +2. 素材列表将只显示属于该分类的素材 +3. 分类按钮会高亮显示当前选中状态 + +### 3. 查看所有素材 +1. 点击"全部"按钮 +2. 清除分类筛选,显示所有素材 + +### 4. 组合筛选 +- 可以同时使用分类筛选和其他筛选条件 +- 例如:选择"商业"分类 + "已使用"状态 +- 筛选条件会叠加生效 + +## 🎨 分类匹配规则 + +### 1. 标签匹配(优先级最高) +- 素材标签完全匹配分类名称 +- 素材标签包含分类名称关键词 + +**示例**: +- 分类:"商业" +- 匹配标签:["商业", "商业宣传", "商务"] + +### 2. 文件名匹配 +- 文件名包含分类名称 +- 文件名包含分类相关关键词 + +**示例**: +- 分类:"教育" +- 匹配文件名:`教育培训视频.mp4`, `education_demo.mp4` + +### 3. AI提示匹配 +- 根据分类的AI识别提示中的关键词匹配 +- 支持多关键词匹配 + +**示例**: +- 分类:"科技",AI提示:"科技,技术,创新,数字化" +- 匹配素材:包含"技术"、"创新"等关键词的素材 + +## 📊 数量统计说明 + +### 统计规则 +- **全部**: 项目中所有素材的总数 +- **具体分类**: 符合该分类匹配规则的素材数量 +- **实时更新**: 添加/删除素材时自动更新 + +### 显示格式 +``` +全部 (15) # 总共15个素材 +商业 (5) # 5个商业类素材 +教育 (3) # 3个教育类素材 +科技 (2) # 2个科技类素材 +其他 (5) # 5个其他类素材 +``` + +## 🎯 最佳实践 + +### 1. 素材标签规范 +- **统一命名**: 使用标准的分类名称作为标签 +- **多标签**: 一个素材可以有多个相关标签 +- **中英文**: 支持中英文标签匹配 + +**推荐标签示例**: +``` +商业素材: ["商业", "business", "商务", "企业"] +教育素材: ["教育", "education", "培训", "学习"] +科技素材: ["科技", "technology", "技术", "创新"] +``` + +### 2. 文件命名规范 +- **包含关键词**: 文件名包含分类相关关键词 +- **描述性命名**: 使用有意义的文件名 +- **避免特殊字符**: 使用标准字符命名 + +**推荐文件名示例**: +``` +商业_产品介绍_2024.mp4 +教育_在线课程_demo.mp4 +科技_AI演示_v1.mp4 +``` + +### 3. 分类管理建议 +- **合理分类**: 创建符合项目需求的分类 +- **颜色区分**: 为不同分类设置不同颜色 +- **AI提示**: 设置准确的AI识别关键词 + +## 🔍 故障排除 + +### 问题1: 素材没有被正确分类 + +**可能原因**: +- 素材标签不匹配分类名称 +- 文件名不包含相关关键词 +- 分类的AI提示设置不准确 + +**解决方案**: +1. 检查素材标签,添加相关分类标签 +2. 重命名文件,包含分类关键词 +3. 更新分类的AI识别提示 + +### 问题2: 分类数量显示不正确 + +**可能原因**: +- 匹配规则过于宽泛或严格 +- 素材数据未及时更新 + +**解决方案**: +1. 刷新页面重新加载数据 +2. 检查分类匹配规则设置 +3. 验证素材标签和文件名 + +### 问题3: 分类加载失败 + +**可能原因**: +- 网络连接问题 +- 分类服务异常 + +**解决方案**: +1. 检查网络连接 +2. 刷新页面重试 +3. 查看浏览器控制台错误信息 + +## 🚀 未来扩展 + +### 计划功能 +- **自动分类**: AI自动为新上传的素材分配分类 +- **批量分类**: 批量修改素材的分类标签 +- **分类统计**: 更详细的分类使用统计报告 +- **自定义分类**: 项目级别的自定义分类 + +### 性能优化 +- **缓存机制**: 缓存分类数据减少加载时间 +- **懒加载**: 大量分类时的分页加载 +- **搜索功能**: 分类名称搜索功能 + +--- + +通过素材分类筛选功能,用户可以更高效地管理和查找项目中的素材,提升工作效率! diff --git a/src/components/ProjectMaterialsCenter.tsx b/src/components/ProjectMaterialsCenter.tsx index 8e8ff83..be7ad42 100644 --- a/src/components/ProjectMaterialsCenter.tsx +++ b/src/components/ProjectMaterialsCenter.tsx @@ -1,8 +1,9 @@ -import React, { useState } from 'react' -import { Video, Play, Search, Filter, Tag, Clock, HardDrive, Eye, User } from 'lucide-react' +import React, { useState, useEffect } from 'react' +import { Video, Play, Search, Filter, Tag, Clock, HardDrive, Eye, User, Folder } from 'lucide-react' import { Project } from '../services/projectService' import { VideoSegment, MediaService } from '../services/mediaService' import { Model } from '../services/modelService' +import { ResourceCategory, ResourceCategoryService } from '../services/resourceCategoryService' import VideoPlayer from './VideoPlayer' interface ProjectMaterialsCenterProps { @@ -25,6 +26,52 @@ const ProjectMaterialsCenter: React.FC = ({ const [selectedMaterial, setSelectedMaterial] = useState(null) const [showVideoPlayer, setShowVideoPlayer] = useState(false) + // 素材分类相关状态 + const [categories, setCategories] = useState([]) + const [selectedCategoryId, setSelectedCategoryId] = useState('') + const [loadingCategories, setLoadingCategories] = useState(false) + + // 加载分类数据 + useEffect(() => { + loadCategories() + }, []) + + const loadCategories = async () => { + setLoadingCategories(true) + try { + const response = await ResourceCategoryService.getAllCategories() + if (response.status && response.data) { + setCategories(response.data.filter(cat => cat.is_active)) + } + } catch (error) { + console.error('Failed to load categories:', error) + } finally { + setLoadingCategories(false) + } + } + + // 计算每个分类的素材数量 + const getCategoryMaterialCount = (categoryId: string): number => { + if (!categoryId) return materials.length // 全部分类 + + const category = categories.find(cat => cat.id === categoryId) + if (!category) return 0 + + return materials.filter(material => { + const categoryTitle = category.title.toLowerCase() + const materialTags = (material.tags || []).map(tag => tag.toLowerCase()) + const filename = material.filename.toLowerCase() + + return materialTags.includes(categoryTitle) || + materialTags.some(tag => tag.includes(categoryTitle)) || + filename.includes(categoryTitle) || + Boolean(category.ai_prompt && + category.ai_prompt.toLowerCase().split(/[,,、\s]+/) + .some(keyword => keyword.length > 1 && + (materialTags.includes(keyword) || filename.includes(keyword)))) + }).length + } + // 过滤素材 const filteredMaterials = materials.filter(material => { // 搜索过滤 @@ -54,7 +101,28 @@ const ProjectMaterialsCenter: React.FC = ({ matchesUsage = material.use_count === 0 } - return matchesSearch && matchesModel && matchesType && matchesUsage + // 分类过滤 + let matchesCategory = true + if (selectedCategoryId) { + const category = categories.find(cat => cat.id === selectedCategoryId) + if (category) { + // 检查素材标签是否包含分类标题,或者文件名是否包含分类相关关键词 + const categoryTitle = category.title.toLowerCase() + const materialTags = (material.tags || []).map(tag => tag.toLowerCase()) + const filename = material.filename.toLowerCase() + + matchesCategory = materialTags.includes(categoryTitle) || + materialTags.some(tag => tag.includes(categoryTitle)) || + filename.includes(categoryTitle) || + // 检查AI提示中的关键词 + Boolean(category.ai_prompt && + category.ai_prompt.toLowerCase().split(/[,,、\s]+/) + .some(keyword => keyword.length > 1 && + (materialTags.includes(keyword) || filename.includes(keyword)))) + } + } + + return matchesSearch && matchesModel && matchesType && matchesUsage && matchesCategory }) const handleModelToggle = (modelId: string) => { @@ -213,6 +281,53 @@ const ProjectMaterialsCenter: React.FC = ({ ))} + + {/* 素材分类过滤 */} +
+
+ + 分类: +
+
+ + {loadingCategories ? ( +
加载中...
+ ) : ( + categories.map((category) => { + const count = getCategoryMaterialCount(category.id) + return ( + + ) + }) + )} +
+
@@ -222,13 +337,13 @@ const ProjectMaterialsCenter: React.FC = ({