fix: 修复项目详情页面模板绑定和素材绑定页面的搜索功能
- 修复项目详情页面模板绑定搜索功能:使用过滤后的绑定详情而不是原始数据 - 修复素材绑定页面搜索功能:添加useEffect监听搜索条件变化并重新加载数据 - 修复素材绑定页面统计功能:实现全局模特绑定统计API和前端调用 - 优化MaterialModelBindingService的getMaterialsByFilter方法,正确处理多重过滤条件 - 添加后端get_global_model_binding_stats命令和相关仓库方法 - 确保搜索和统计功能在所有相关页面正常工作
This commit is contained in:
parent
03f410601a
commit
de446b6410
|
|
@ -919,6 +919,28 @@ impl MaterialService {
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
/// 获取全局模特绑定统计
|
||||
pub fn get_global_model_binding_stats(
|
||||
repository: &MaterialRepository,
|
||||
) -> Result<ProjectModelBindingStats> {
|
||||
debug!("获取全局模特绑定统计");
|
||||
|
||||
let bound_count = repository.count_global_bound_materials()?;
|
||||
let unbound_count = repository.count_global_unbound_materials()?;
|
||||
let total_count = bound_count + unbound_count;
|
||||
|
||||
Ok(ProjectModelBindingStats {
|
||||
total_materials: total_count,
|
||||
bound_materials: bound_count,
|
||||
unbound_materials: unbound_count,
|
||||
binding_rate: if total_count > 0 {
|
||||
(bound_count as f64 / total_count as f64) * 100.0
|
||||
} else {
|
||||
0.0
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// 项目模特绑定统计信息
|
||||
|
|
|
|||
|
|
@ -643,6 +643,32 @@ impl MaterialRepository {
|
|||
|
||||
Ok(count as u32)
|
||||
}
|
||||
|
||||
/// 获取全局绑定了模特的素材数量
|
||||
pub fn count_global_bound_materials(&self) -> Result<u32> {
|
||||
let conn = self.connection.lock().unwrap();
|
||||
|
||||
let count: i64 = conn.query_row(
|
||||
"SELECT COUNT(*) FROM materials WHERE model_id IS NOT NULL",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
|
||||
Ok(count as u32)
|
||||
}
|
||||
|
||||
/// 获取全局未绑定模特的素材数量
|
||||
pub fn count_global_unbound_materials(&self) -> Result<u32> {
|
||||
let conn = self.connection.lock().unwrap();
|
||||
|
||||
let count: i64 = conn.query_row(
|
||||
"SELECT COUNT(*) FROM materials WHERE model_id IS NULL",
|
||||
[],
|
||||
|row| row.get(0),
|
||||
)?;
|
||||
|
||||
Ok(count as u32)
|
||||
}
|
||||
}
|
||||
|
||||
/// 模特素材统计信息
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ pub fn run() {
|
|||
commands::material_commands::switch_material_model,
|
||||
commands::material_commands::get_model_material_statistics,
|
||||
commands::material_commands::get_project_model_binding_stats,
|
||||
commands::material_commands::get_global_model_binding_stats,
|
||||
commands::material_commands::update_material,
|
||||
// 模特管理命令
|
||||
commands::model_commands::create_model,
|
||||
|
|
|
|||
|
|
@ -1013,6 +1013,21 @@ pub async fn get_project_model_binding_stats(
|
|||
.map_err(|e| format!("获取项目模特绑定统计失败: {}", e))
|
||||
}
|
||||
|
||||
/// 获取全局模特绑定统计信息命令
|
||||
#[command]
|
||||
pub async fn get_global_model_binding_stats(
|
||||
state: State<'_, AppState>,
|
||||
) -> Result<crate::business::services::material_service::ProjectModelBindingStats, String> {
|
||||
let repository_guard = state.get_material_repository()
|
||||
.map_err(|e| format!("获取素材仓库失败: {}", e))?;
|
||||
|
||||
let repository = repository_guard.as_ref()
|
||||
.ok_or("素材仓库未初始化")?;
|
||||
|
||||
MaterialService::get_global_model_binding_stats(repository)
|
||||
.map_err(|e| format!("获取全局模特绑定统计失败: {}", e))
|
||||
}
|
||||
|
||||
/// 更新素材信息命令(包括模特绑定)
|
||||
#[command]
|
||||
pub async fn update_material(
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const MaterialModelBinding: React.FC = () => {
|
|||
|
||||
const [materials, setMaterials] = useState<Material[]>([]);
|
||||
const [models, setModels] = useState<Model[]>([]);
|
||||
const [stats] = useState<MaterialModelBindingStats | null>(null);
|
||||
const [stats, setStats] = useState<MaterialModelBindingStats | null>(null);
|
||||
const [selectedModel, setSelectedModel] = useState<string>('');
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [filterType, setFilterType] = useState<'all' | 'bound' | 'unbound'>('all');
|
||||
|
|
@ -50,6 +50,13 @@ export const MaterialModelBinding: React.FC = () => {
|
|||
loadData();
|
||||
}, []);
|
||||
|
||||
// 当搜索条件变化时重新加载素材
|
||||
useEffect(() => {
|
||||
if (searchQuery !== '' || filterType !== 'all' || selectedModel !== '') {
|
||||
loadMaterials();
|
||||
}
|
||||
}, [searchQuery, filterType, selectedModel]);
|
||||
|
||||
const loadData = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
|
|
@ -92,9 +99,8 @@ export const MaterialModelBinding: React.FC = () => {
|
|||
|
||||
const loadStats = async () => {
|
||||
try {
|
||||
// 这里需要一个获取全局统计的API,暂时跳过
|
||||
// const statsData = await invoke<MaterialModelBindingStats>('get_global_model_binding_stats');
|
||||
// setStats(statsData);
|
||||
const statsData = await MaterialModelBindingService.getGlobalModelBindingStats();
|
||||
setStats(statsData);
|
||||
} catch (err) {
|
||||
console.error('加载统计失败:', err);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,6 +61,16 @@ export const ProjectDetails: React.FC = () => {
|
|||
actions: bindingActions
|
||||
} = useProjectTemplateBindingStore();
|
||||
|
||||
// 获取过滤后的绑定详情
|
||||
const filteredBindingDetails = React.useMemo(() => {
|
||||
if (!bindingDetails.length) return [];
|
||||
|
||||
const filteredBindings = bindingActions.getFilteredBindings();
|
||||
return bindingDetails.filter(detail =>
|
||||
filteredBindings.some(binding => binding.id === detail.binding.id)
|
||||
);
|
||||
}, [bindingDetails, bindingFilters, bindingActions]);
|
||||
|
||||
// 模板状态管理
|
||||
const { templates, fetchTemplates } = useTemplateStore();
|
||||
|
||||
|
|
@ -607,7 +617,7 @@ export const ProjectDetails: React.FC = () => {
|
|||
)}
|
||||
|
||||
<ProjectTemplateBindingList
|
||||
bindings={bindingDetails}
|
||||
bindings={filteredBindingDetails}
|
||||
loading={bindingLoading}
|
||||
selectedIds={selectedBindingIds}
|
||||
onSelectionChange={bindingActions.setSelectedBindingIds}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,13 @@ export class MaterialModelBindingService {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取全局模特绑定统计信息
|
||||
*/
|
||||
static async getGlobalModelBindingStats(): Promise<MaterialModelBindingStats> {
|
||||
return await invoke<MaterialModelBindingStats>('get_global_model_binding_stats');
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新素材信息
|
||||
*/
|
||||
|
|
@ -156,32 +163,34 @@ export class MaterialModelBindingService {
|
|||
bound?: boolean;
|
||||
search?: string;
|
||||
}): Promise<Material[]> {
|
||||
let materials: Material[] = [];
|
||||
|
||||
// 首先根据主要过滤条件获取素材
|
||||
if (filter.modelId) {
|
||||
return this.getMaterialsByModel(filter.modelId);
|
||||
}
|
||||
|
||||
if (filter.bound === false) {
|
||||
return this.getUnboundMaterials(filter.projectId);
|
||||
}
|
||||
|
||||
if (filter.projectId) {
|
||||
const materials = await this.getProjectMaterials(filter.projectId);
|
||||
|
||||
materials = await this.getMaterialsByModel(filter.modelId);
|
||||
} else if (filter.bound === false) {
|
||||
materials = await this.getUnboundMaterials(filter.projectId);
|
||||
} else if (filter.projectId) {
|
||||
materials = await this.getProjectMaterials(filter.projectId);
|
||||
|
||||
// 如果指定了绑定状态过滤
|
||||
if (filter.bound === true) {
|
||||
return materials.filter(m => m.model_id);
|
||||
materials = materials.filter(m => m.model_id);
|
||||
}
|
||||
|
||||
if (filter.search) {
|
||||
return materials.filter(m =>
|
||||
m.name.toLowerCase().includes(filter.search!.toLowerCase())
|
||||
);
|
||||
}
|
||||
|
||||
return materials;
|
||||
} else {
|
||||
// 如果没有指定项目,返回空数组
|
||||
return [];
|
||||
}
|
||||
|
||||
// 如果没有指定项目,返回空数组
|
||||
return [];
|
||||
|
||||
// 应用搜索过滤
|
||||
if (filter.search && filter.search.trim()) {
|
||||
const searchLower = filter.search.toLowerCase();
|
||||
materials = materials.filter(m =>
|
||||
m.name.toLowerCase().includes(searchLower)
|
||||
);
|
||||
}
|
||||
|
||||
return materials;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
Loading…
Reference in New Issue