fix: 修复ProjectDetails.tsx中的无限请求问题和模特名称显示
- 修复loadProjectClassificationStats函数的无限循环问题 - 使用useRef跟踪分类统计加载状态,避免重复请求 - 添加模特信息加载功能,显示真实模特名称而非model_id - 优化useEffect依赖,防止不必要的重新渲染和请求 - 在项目切换和导入完成时正确重置加载状态
This commit is contained in:
parent
08fa4eda61
commit
52ce437e63
|
|
@ -29,7 +29,6 @@ pub async fn get_model_by_id(
|
||||||
state: State<'_, AppState>,
|
state: State<'_, AppState>,
|
||||||
id: String,
|
id: String,
|
||||||
) -> Result<Option<Model>, String> {
|
) -> Result<Option<Model>, String> {
|
||||||
println!("get_model_by_id 命令开始执行,ID: {}", id);
|
|
||||||
|
|
||||||
let repository_guard = state.get_model_repository()
|
let repository_guard = state.get_model_repository()
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
|
|
@ -43,14 +42,12 @@ pub async fn get_model_by_id(
|
||||||
"模特仓库未初始化".to_string()
|
"模特仓库未初始化".to_string()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
println!("调用 ModelService::get_model_by_id");
|
|
||||||
let result = ModelService::get_model_by_id(repository, &id)
|
let result = ModelService::get_model_by_id(repository, &id)
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
println!("ModelService::get_model_by_id 失败: {}", e);
|
println!("ModelService::get_model_by_id 失败: {}", e);
|
||||||
e.to_string()
|
e.to_string()
|
||||||
});
|
});
|
||||||
|
|
||||||
println!("get_model_by_id 命令执行完成,结果: {:?}", result.is_ok());
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import React, { useEffect, useState, useCallback, useMemo } from 'react';
|
import React, { useEffect, useState, useCallback, useMemo, useRef } from 'react';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { ArrowLeft, FolderOpen, Upload, FileVideo, FileAudio, FileImage, HardDrive, Brain, Loader2, Link, Layers, Calendar, MapPin, Users, CheckCircle, Filter } from 'lucide-react';
|
import { ArrowLeft, FolderOpen, Upload, FileVideo, FileAudio, FileImage, HardDrive, Brain, Loader2, Link, Layers, Calendar, MapPin, Users, CheckCircle, Filter } from 'lucide-react';
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
|
|
@ -134,6 +134,10 @@ export const ProjectDetails: React.FC = () => {
|
||||||
const [materialModelFilter, setMaterialModelFilter] = useState<string>('全部');
|
const [materialModelFilter, setMaterialModelFilter] = useState<string>('全部');
|
||||||
const [materialUsageFilter, setMaterialUsageFilter] = useState<string>('全部');
|
const [materialUsageFilter, setMaterialUsageFilter] = useState<string>('全部');
|
||||||
const [materialClassificationRecords, setMaterialClassificationRecords] = useState<{[materialId: string]: any[]}>({});
|
const [materialClassificationRecords, setMaterialClassificationRecords] = useState<{[materialId: string]: any[]}>({});
|
||||||
|
const [modelsMap, setModelsMap] = useState<{[modelId: string]: any}>({});
|
||||||
|
|
||||||
|
// 用于跟踪分类统计是否已加载的ref
|
||||||
|
const classificationStatsLoadedRef = useRef<string | null>(null);
|
||||||
|
|
||||||
// 加载片段统计数据
|
// 加载片段统计数据
|
||||||
const loadSegmentStats = useCallback(async (projectId: string) => {
|
const loadSegmentStats = useCallback(async (projectId: string) => {
|
||||||
|
|
@ -155,12 +159,30 @@ export const ProjectDetails: React.FC = () => {
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// 加载项目分类统计信息
|
// 加载所有模特信息
|
||||||
const loadProjectClassificationStats = useCallback(async (projectId: string) => {
|
const loadAllModels = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
|
const models = await invoke('get_all_models') as any[];
|
||||||
|
const modelMap: {[modelId: string]: any} = {};
|
||||||
|
models.forEach(model => {
|
||||||
|
modelMap[model.id] = model;
|
||||||
|
});
|
||||||
|
setModelsMap(modelMap);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to load models:', error);
|
||||||
|
setModelsMap({});
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// 加载项目分类统计信息
|
||||||
|
const loadProjectClassificationStats = useCallback(async (projectId: string, materialList?: any[]) => {
|
||||||
|
try {
|
||||||
|
// 使用传入的素材列表或当前的素材列表
|
||||||
|
const materialsToProcess = materialList || materials;
|
||||||
|
|
||||||
// 获取每个素材的分类记录
|
// 获取每个素材的分类记录
|
||||||
const classificationRecords: {[materialId: string]: any[]} = {};
|
const classificationRecords: {[materialId: string]: any[]} = {};
|
||||||
for (const material of materials) {
|
for (const material of materialsToProcess) {
|
||||||
try {
|
try {
|
||||||
const records = await invoke('get_material_classification_records', { materialId: material.id }) as any[];
|
const records = await invoke('get_material_classification_records', { materialId: material.id }) as any[];
|
||||||
classificationRecords[material.id] = records;
|
classificationRecords[material.id] = records;
|
||||||
|
|
@ -175,7 +197,7 @@ export const ProjectDetails: React.FC = () => {
|
||||||
console.error('Failed to load project classification stats:', error);
|
console.error('Failed to load project classification stats:', error);
|
||||||
setMaterialClassificationRecords({});
|
setMaterialClassificationRecords({});
|
||||||
}
|
}
|
||||||
}, [materials]);
|
}, []);
|
||||||
|
|
||||||
// 加载项目详情
|
// 加载项目详情
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -192,6 +214,9 @@ export const ProjectDetails: React.FC = () => {
|
||||||
|
|
||||||
// 加载项目素材
|
// 加载项目素材
|
||||||
if (foundProject) {
|
if (foundProject) {
|
||||||
|
// 重置分类统计加载状态
|
||||||
|
classificationStatsLoadedRef.current = null;
|
||||||
|
|
||||||
loadMaterials(foundProject.id);
|
loadMaterials(foundProject.id);
|
||||||
loadMaterialStats(foundProject.id);
|
loadMaterialStats(foundProject.id);
|
||||||
// 加载项目的模板绑定
|
// 加载项目的模板绑定
|
||||||
|
|
@ -200,18 +225,20 @@ export const ProjectDetails: React.FC = () => {
|
||||||
loadSegmentStats(foundProject.id);
|
loadSegmentStats(foundProject.id);
|
||||||
// 加载素材使用状态概览
|
// 加载素材使用状态概览
|
||||||
loadUsageOverview(foundProject.id);
|
loadUsageOverview(foundProject.id);
|
||||||
// 加载项目分类统计信息
|
// 加载所有模特信息
|
||||||
loadProjectClassificationStats(foundProject.id);
|
loadAllModels();
|
||||||
|
// 加载项目分类统计信息将在素材加载完成后执行
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [id, projects, loadMaterials, loadMaterialStats, bindingActions.fetchTemplatesByProject, loadSegmentStats, loadUsageOverview, loadProjectClassificationStats]);
|
}, [id, projects, loadMaterials, loadMaterialStats, bindingActions.fetchTemplatesByProject, loadSegmentStats, loadUsageOverview, loadAllModels, loadProjectClassificationStats]);
|
||||||
|
|
||||||
// 当素材列表变化时,重新加载分类统计信息
|
// 当素材加载完成后,加载分类统计信息
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (project && materials.length > 0) {
|
if (project && materials.length > 0 && classificationStatsLoadedRef.current !== project.id) {
|
||||||
loadProjectClassificationStats(project.id);
|
classificationStatsLoadedRef.current = project.id;
|
||||||
|
loadProjectClassificationStats(project.id, materials);
|
||||||
}
|
}
|
||||||
}, [materials.length, project, loadProjectClassificationStats]);
|
}, [project?.id, materials.length, loadProjectClassificationStats]);
|
||||||
|
|
||||||
// 加载模板列表
|
// 加载模板列表
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -284,6 +311,8 @@ export const ProjectDetails: React.FC = () => {
|
||||||
console.log('导入完成:', result);
|
console.log('导入完成:', result);
|
||||||
// 重新加载素材列表
|
// 重新加载素材列表
|
||||||
if (project) {
|
if (project) {
|
||||||
|
// 重置分类统计加载状态,以便重新加载
|
||||||
|
classificationStatsLoadedRef.current = null;
|
||||||
loadMaterials(project.id);
|
loadMaterials(project.id);
|
||||||
loadMaterialStats(project.id);
|
loadMaterialStats(project.id);
|
||||||
}
|
}
|
||||||
|
|
@ -591,7 +620,6 @@ export const ProjectDetails: React.FC = () => {
|
||||||
const modelCounts: {[key: string]: number} = {};
|
const modelCounts: {[key: string]: number} = {};
|
||||||
materials.forEach(material => {
|
materials.forEach(material => {
|
||||||
if (material.model_id) {
|
if (material.model_id) {
|
||||||
// 这里需要根据model_id获取模特名称,暂时使用model_id
|
|
||||||
const modelKey = material.model_id;
|
const modelKey = material.model_id;
|
||||||
modelCounts[modelKey] = (modelCounts[modelKey] || 0) + 1;
|
modelCounts[modelKey] = (modelCounts[modelKey] || 0) + 1;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -600,15 +628,26 @@ export const ProjectDetails: React.FC = () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.entries(modelCounts).forEach(([modelKey, count]) => {
|
Object.entries(modelCounts).forEach(([modelKey, count]) => {
|
||||||
|
let label = '未指定';
|
||||||
|
if (modelKey !== '未指定') {
|
||||||
|
// 从modelsMap中获取模特的真实名称
|
||||||
|
const model = modelsMap[modelKey];
|
||||||
|
if (model) {
|
||||||
|
label = model.stage_name || model.name;
|
||||||
|
} else {
|
||||||
|
label = `模特-${modelKey}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
label: modelKey === '未指定' ? '未指定' : `模特-${modelKey}`,
|
label,
|
||||||
value: modelKey,
|
value: modelKey,
|
||||||
count
|
count
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}, [materials]);
|
}, [materials, modelsMap]);
|
||||||
|
|
||||||
const materialUsageOptions = useMemo(() => {
|
const materialUsageOptions = useMemo(() => {
|
||||||
// 计算使用状态统计
|
// 计算使用状态统计
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue