auto refresh workspace preview
This commit is contained in:
@@ -30,7 +30,6 @@ import {
|
||||
FolderOpen,
|
||||
Server,
|
||||
AlertCircle,
|
||||
Eye,
|
||||
Info,
|
||||
X
|
||||
} from 'lucide-react';
|
||||
@@ -464,27 +463,42 @@ export default function App() {
|
||||
showToast('密码更新成功');
|
||||
};
|
||||
|
||||
const handleUpdatePreview = async () => {
|
||||
setIsPreviewLoading(true);
|
||||
try {
|
||||
const data = await apiRequest('/api/preview', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
inputDir: selectedInputDir,
|
||||
angleDegrees: cervicalRotation
|
||||
})
|
||||
});
|
||||
setPreviewImage(data.image);
|
||||
setBackendOnline(true);
|
||||
setBackendMessage('预览已由 head_extension_app.py 生成');
|
||||
showToast('预览已更新');
|
||||
} catch (error) {
|
||||
setBackendOnline(false);
|
||||
showToast((error as Error).message);
|
||||
} finally {
|
||||
setIsPreviewLoading(false);
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
if (currentPage !== 'workspace' || !selectedInputDir) return;
|
||||
|
||||
const controller = new AbortController();
|
||||
const timer = window.setTimeout(async () => {
|
||||
setIsPreviewLoading(true);
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/api/preview`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
inputDir: selectedInputDir,
|
||||
angleDegrees: cervicalRotation
|
||||
}),
|
||||
signal: controller.signal
|
||||
});
|
||||
const data = await response.json();
|
||||
if (!response.ok) throw new Error(data.error || '预览生成失败');
|
||||
setPreviewImage(data.image);
|
||||
setBackendOnline(true);
|
||||
setBackendMessage('预览已自动更新');
|
||||
} catch (error) {
|
||||
if ((error as Error).name !== 'AbortError') {
|
||||
setBackendOnline(false);
|
||||
setBackendMessage((error as Error).message);
|
||||
}
|
||||
} finally {
|
||||
if (!controller.signal.aborted) setIsPreviewLoading(false);
|
||||
}
|
||||
}, 300);
|
||||
|
||||
return () => {
|
||||
controller.abort();
|
||||
window.clearTimeout(timer);
|
||||
};
|
||||
}, [currentPage, selectedInputDir, cervicalRotation]);
|
||||
|
||||
const handleRunSimulation = async () => {
|
||||
if (isSimulating) return;
|
||||
@@ -694,11 +708,8 @@ export default function App() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<button onClick={handleUpdatePreview} disabled={isPreviewLoading || !selectedInputDir} className="py-3 bg-slate-900 text-white rounded-xl text-xs font-bold hover:bg-slate-700 transition-all flex items-center justify-center gap-2 active:scale-95 disabled:opacity-50">
|
||||
<Eye size={14} /> {isPreviewLoading ? '预览中' : '更新预览'}
|
||||
</button>
|
||||
<button onClick={handleRunSimulation} disabled={isSimulating || !selectedInputDir} className="py-3 bg-blue-600 text-white rounded-xl text-xs font-bold hover:bg-blue-700 transition-all flex items-center justify-center gap-2 active:scale-95 disabled:opacity-50">
|
||||
<div>
|
||||
<button onClick={handleRunSimulation} disabled={isSimulating || !selectedInputDir} className="w-full py-3 bg-blue-600 text-white rounded-xl text-xs font-bold hover:bg-blue-700 transition-all flex items-center justify-center gap-2 active:scale-95 disabled:opacity-50">
|
||||
<PlayIcon className="fill-white" size={14} /> {isSimulating ? '生成中' : '四状态输出'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -774,7 +785,10 @@ export default function App() {
|
||||
<h4 className="font-black text-slate-800">快速 2D 预览</h4>
|
||||
<p className="text-[10px] text-slate-400 font-bold mt-1">对应 head_extension_app.py 的 preview_deform_2d</p>
|
||||
</div>
|
||||
<span className="text-[10px] font-mono text-slate-400">{cervicalRotation.toFixed(1)} DEG</span>
|
||||
<div className="text-right">
|
||||
<span className="text-[10px] font-mono text-slate-400">{cervicalRotation.toFixed(1)} DEG</span>
|
||||
{isPreviewLoading && <p className="text-[9px] font-bold text-blue-500 mt-1">自动更新中...</p>}
|
||||
</div>
|
||||
</div>
|
||||
<div className="h-[360px] bg-slate-950 flex items-center justify-center">
|
||||
{previewImage ? (
|
||||
@@ -782,7 +796,7 @@ export default function App() {
|
||||
) : (
|
||||
<div className="text-center text-slate-500">
|
||||
<ImageIcon size={42} className="mx-auto mb-3 opacity-40" />
|
||||
<p className="text-xs font-bold">点击“更新预览”读取影像库 DICOM</p>
|
||||
<p className="text-xs font-bold">{isPreviewLoading ? '正在自动生成预览...' : '选择影像库数据后自动生成预览'}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user