feat: update analysis workflow UI
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useState, useCallback, useEffect, useRef, useMemo } from 'react';
|
||||
import { useState, useCallback, useEffect, useMemo } from 'react';
|
||||
import { useAuth } from '@/_core/hooks/useAuth';
|
||||
import { getLoginUrl } from '@/const';
|
||||
import PointCloudViewer from '@/components/PointCloudViewer';
|
||||
@@ -7,7 +7,6 @@ import TaskManager from '@/components/TaskManager';
|
||||
import AnalysisPanel from '@/components/AnalysisPanel';
|
||||
import AlgorithmRunPanel from '@/components/AlgorithmRunPanel';
|
||||
import type { Overlay3D } from '@/components/GenericResultView';
|
||||
import WorkflowProgress, { type WorkflowState, type WorkflowStepId, type StepStatus } from '@/components/WorkflowProgress';
|
||||
import { trpc } from '@/lib/trpc';
|
||||
import {
|
||||
LogIn,
|
||||
@@ -90,11 +89,6 @@ export default function Home() {
|
||||
overlay: Overlay3D;
|
||||
} | null>(null);
|
||||
const [errorPickEnabled, setErrorPickEnabled] = useState(false);
|
||||
const [isCreatingTask, setIsCreatingTask] = useState(false);
|
||||
// 触发分析时的 completed 结果基线数(key=taskId, value=触发时已有的 completed 数)
|
||||
const [analysisBaselines, setAnalysisBaselines] = useState<Map<number, number>>(new Map());
|
||||
// 用 ref 在 onSuccess 闭包中读取最新 analysisResults,避免过时闭包
|
||||
const analysisResultsRef = useRef<any[]>([]);
|
||||
const [showLeftPanel, setShowLeftPanel] = useState(true);
|
||||
const [showRightPanel, setShowRightPanel] = useState(true);
|
||||
|
||||
@@ -122,13 +116,6 @@ export default function Home() {
|
||||
toast.success('已提交偏差热力分析(STL/OBJ + 点云距离),完成后点击「在 3D 中查看」');
|
||||
}
|
||||
void utils.analysisResult.list.invalidate({ taskId: variables.taskId });
|
||||
// 记录此时已有的 completed 数作为基线,只有新增结果才算本次分析完成
|
||||
const baselineCount = analysisResultsRef.current.filter((r: any) => r.status === 'completed').length;
|
||||
setAnalysisBaselines(prev => {
|
||||
const next = new Map(prev);
|
||||
if (!next.has(variables.taskId)) next.set(variables.taskId, baselineCount);
|
||||
return next;
|
||||
});
|
||||
},
|
||||
onError: (e) => toast.error(e.message || '提交失败'),
|
||||
});
|
||||
@@ -146,7 +133,6 @@ export default function Home() {
|
||||
setHeatmapViewResultId(null);
|
||||
setPluginOverlay(null);
|
||||
setPointCloudRenderMode('points');
|
||||
setIsCreatingTask(false);
|
||||
setSelectedPcFileIds([]);
|
||||
setSelectedTaskCadFileIds([]);
|
||||
setRoiPickMode(false);
|
||||
@@ -253,57 +239,6 @@ export default function Home() {
|
||||
// ── 把 __task:N 格式的 URL 转成 batch 请求参数 ──────────────────────────────
|
||||
const batchTaskId = pointCloudTaskId;
|
||||
|
||||
// ── 工作流进度条状态推导 ───────────────────────────────────────────────────
|
||||
const { data: analysisResults = [] } = trpc.analysisResult.list.useQuery(
|
||||
{ taskId: selection.taskId! },
|
||||
{ enabled: selection.taskId != null, refetchInterval: 5000 },
|
||||
);
|
||||
|
||||
useEffect(() => { analysisResultsRef.current = analysisResults; }, [analysisResults]);
|
||||
|
||||
const workflowState = useMemo<WorkflowState>(() => {
|
||||
const hasCad = !!cadModelUrl;
|
||||
const hasPc = pointCloudTaskId != null;
|
||||
const rendered = hasPc && !pcLoading && pcProgress >= 100;
|
||||
const baseline = (!isCreatingTask && selection.taskId != null)
|
||||
? (analysisBaselines.get(selection.taskId) ?? -1)
|
||||
: -1;
|
||||
const triggered = baseline >= 0;
|
||||
const currentCompleted = (analysisResults as any[]).filter((r: any) => r.status === 'completed').length;
|
||||
const analyzed = triggered && currentCompleted > baseline;
|
||||
|
||||
function step(cond: boolean, prev: boolean): 'done' | 'active' | 'pending' {
|
||||
if (cond) return 'done';
|
||||
if (prev) return 'active';
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
// 分析步骤:只在 触发后未完成 时转圈;保存步骤:分析完成即完成,无中间态
|
||||
const analysisStatus: StepStatus = analyzed ? 'done' : triggered ? 'active' : 'pending';
|
||||
const saveStatus: StepStatus = analyzed ? 'done' : 'pending';
|
||||
|
||||
return {
|
||||
cad: step(hasCad, true),
|
||||
pointcloud: step(hasPc, hasCad),
|
||||
render: step(rendered, hasPc),
|
||||
analysis: analysisStatus,
|
||||
save: saveStatus,
|
||||
};
|
||||
}, [cadModelUrl, pointCloudTaskId, pcLoading, pcProgress, analysisResults, isCreatingTask, analysisBaselines, selection.taskId]);
|
||||
|
||||
const rightPanelRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const handleWorkflowStepClick = useCallback((id: WorkflowStepId) => {
|
||||
if (id === 'cad' || id === 'pointcloud') {
|
||||
setShowLeftPanel(true);
|
||||
} else if (id === 'render') {
|
||||
if (selection.taskId != null && pointCloudTaskId !== selection.taskId) {
|
||||
handleLoadPointClouds(selection.taskId, []);
|
||||
}
|
||||
} else if (id === 'analysis' || id === 'save') {
|
||||
setShowRightPanel(true);
|
||||
}
|
||||
}, [selection.taskId, pointCloudTaskId, handleLoadPointClouds]);
|
||||
// 必须稳定数组引用:若每次 render 都 new [],PointCloudViewer 会以为点云源变了而反复全量请求
|
||||
const pointCloudUrlsStable = useMemo(
|
||||
() => (pointCloudTaskId != null ? [`__task:${pointCloudTaskId}`] : undefined),
|
||||
@@ -329,8 +264,6 @@ export default function Home() {
|
||||
onPcFilesSelectionChange={setSelectedPcFileIds}
|
||||
onCadFilesSelectionChange={setSelectedTaskCadFileIds}
|
||||
onSelectTaskCad={handleSelectCad}
|
||||
onStartCreate={() => setIsCreatingTask(true)}
|
||||
onEndCreate={() => setIsCreatingTask(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
@@ -350,6 +283,7 @@ export default function Home() {
|
||||
<div className="space-y-4">
|
||||
<AlgorithmRunPanel
|
||||
taskId={selection.taskId}
|
||||
modelId={selection.modelId}
|
||||
pointCloudLoaded={pointCloudTaskId === selection.taskId && pointCloudUrls.length > 0}
|
||||
taskPcFileCount={taskPcFiles.length}
|
||||
taskPointcloudFiles={taskPcFiles}
|
||||
@@ -481,13 +415,6 @@ export default function Home() {
|
||||
|
||||
{/* 中央 3D 视图 */}
|
||||
<main className="flex-1 flex flex-col min-w-0">
|
||||
{/* 工作流进度条(仅在选中任务时显示) */}
|
||||
{selection.taskId != null && (
|
||||
<WorkflowProgress
|
||||
state={workflowState}
|
||||
onStepClick={handleWorkflowStepClick}
|
||||
/>
|
||||
)}
|
||||
<div className="flex-1 relative">
|
||||
<div className="absolute inset-2">
|
||||
<div className="viewer-container w-full h-full relative">
|
||||
@@ -670,7 +597,7 @@ export default function Home() {
|
||||
|
||||
{/* 右侧面板 - 分析结果 */}
|
||||
{showRightPanel && (
|
||||
<aside ref={rightPanelRef} className="w-80 border-l border-border bg-card/30 flex-shrink-0 overflow-y-auto p-3">
|
||||
<aside className="w-80 border-l border-border bg-card/30 flex-shrink-0 overflow-y-auto p-3">
|
||||
{renderRightPanel()}
|
||||
</aside>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user