2026-05-08-03-23-51 精简模型入口和切分显示

This commit is contained in:
2026-05-08 03:26:55 +08:00
parent 3b133a1d43
commit 500a43dbe9
8 changed files with 156 additions and 84 deletions

View File

@@ -28,7 +28,7 @@ export default function App() {
// Automatically collapse main sidebar when entering Project Library or Workspace
useEffect(() => {
if (activeView === ViewType.PROJECTS || activeView === ViewType.MODELS || activeView === ViewType.WORKSPACE) {
if (activeView === ViewType.PROJECTS || activeView === ViewType.WORKSPACE) {
setSidebarCollapsed(true);
} else {
setSidebarCollapsed(false);
@@ -106,7 +106,6 @@ export default function App() {
<span className="text-slate-900 font-bold capitalize">
{activeView === ViewType.OVERVIEW && '总体概况'}
{activeView === ViewType.PROJECTS && '项目库'}
{activeView === ViewType.MODELS && '模型库'}
{activeView === ViewType.WORKSPACE && '逆向工作区'}
{activeView === ViewType.SYSTEM && '系统管理工作区'}
</span>
@@ -136,15 +135,6 @@ export default function App() {
}}
/>
)}
{activeView === ViewType.MODELS && (
<ProjectLibrary
initialViewMode="model"
onReverse={(projectId) => {
setActiveProjectId(projectId);
setActiveView(ViewType.WORKSPACE);
}}
/>
)}
{activeView === ViewType.WORKSPACE && <ReverseWorkspace projectId={activeProjectId} />}
{activeView === ViewType.SYSTEM && <UserManagement />}
</motion.div>

View File

@@ -219,21 +219,6 @@ function FusionThreeView({
const upperCutZ = sliceToZ(cutRangeEnd);
const lowerClippingPlane = new THREE.Plane();
const upperClippingPlane = new THREE.Plane();
const createCutPlaneMaterial = () => new THREE.MeshBasicMaterial({
color: '#f97316',
transparent: true,
opacity: cutEnabled ? 0.16 : 0,
side: THREE.DoubleSide,
depthWrite: false,
});
const lowerCutPlane = new THREE.Mesh(new THREE.PlaneGeometry(dicomWidth, dicomHeight), createCutPlaneMaterial());
lowerCutPlane.position.set(0, 0, lowerCutZ);
lowerCutPlane.visible = cutEnabled;
dicomGroup.add(lowerCutPlane);
const upperCutPlane = new THREE.Mesh(new THREE.PlaneGeometry(dicomWidth, dicomHeight), createCutPlaneMaterial());
upperCutPlane.position.set(0, 0, upperCutZ);
upperCutPlane.visible = cutEnabled;
dicomGroup.add(upperCutPlane);
const textures: THREE.Texture[] = [];
volume.frames.forEach((frame, index) => {
@@ -532,7 +517,6 @@ export default function ReverseWorkspace({ projectId }: { projectId: string }) {
const [fusionError, setFusionError] = useState('');
const [exporting, setExporting] = useState(false);
const [exportMessage, setExportMessage] = useState('准备就绪');
const [preloadMessage, setPreloadMessage] = useState('缓存空闲');
const fusionVolumeCacheRef = useRef(new Map<string, DicomFusionVolume>());
const poseRepeatRef = useRef<{ timeout: number | null; interval: number | null }>({ timeout: null, interval: null });
@@ -594,7 +578,6 @@ export default function ReverseWorkspace({ projectId }: { projectId: string }) {
const cached = fusionVolumeCacheRef.current.get(cacheKey);
if (useCache && cached) {
setFusionVolume(cached);
setPreloadMessage(`已使用缓存范围 ${safeStart + 1}-${rangeEnd + 1}`);
return cached;
}
const volumePayload = await api.getDicomFusionVolume(project.id, safeStart, rangeEnd, 'soft');
@@ -769,29 +752,6 @@ export default function ReverseWorkspace({ projectId }: { projectId: string }) {
const rangeEndPercent = maxSlice > 0 ? (displayEnd / maxSlice) * 100 : 0;
const selectedDisplay = displayOptions.find((item) => item.id === displayLevel) ?? displayOptions[0];
const selectedDicomOpacity = dicomOpacityOptions.find((item) => item.id === dicomOpacityLevel) ?? dicomOpacityOptions[0];
const preloadPoints = [0.2, 0.4, 0.6, 0.8, 1].map((ratio) => clamp(Math.max(0, Math.round((project?.dicomCount ?? 1) * ratio) - 1), 0, maxSlice));
const preloadFusionPoint = async (end: number) => {
if (!project) return;
const safeEnd = clamp(end, 0, maxSlice);
setPreloadMessage(`正在预存第 ${safeEnd + 1} 张...`);
try {
await loadFusionVolume(safeEnd, safeEnd, false);
setPreloadMessage(`已预存第 ${safeEnd + 1}`);
} catch (error) {
setPreloadMessage(error instanceof Error ? error.message : '预存失败');
}
};
const preloadAllFusionPoints = async () => {
setPreloadMessage('正在预存五个点位...');
try {
await Promise.all(preloadPoints.map((point) => loadFusionVolume(point, point, true)));
setPreloadMessage('五个点位已预存');
} catch (error) {
setPreloadMessage(error instanceof Error ? error.message : '五点预存失败');
}
};
return (
<div className="h-full min-h-0 overflow-y-auto pr-2 flex flex-col gap-6">
@@ -911,36 +871,6 @@ export default function ReverseWorkspace({ projectId }: { projectId: string }) {
<span className="text-right"> {safeSliceEnd + 1}</span>
</div>
</div>
<p className="mt-3 text-[10px] leading-5 text-slate-400">
M-N姿
</p>
<div className="mt-3 flex flex-wrap items-center gap-2">
{preloadPoints.map((point, index) => {
const cached = project ? fusionVolumeCacheRef.current.has(getFusionCacheKey(project.id, point, point)) : false;
return (
<button
key={`${point}-${index}`}
onClick={() => {
setSliceStart(point);
setSliceEnd(point);
preloadFusionPoint(point);
}}
className={`rounded-lg border px-2 py-1 text-[10px] font-bold transition-all ${
project && cached ? 'border-emerald-200 bg-emerald-50 text-emerald-600' : 'border-slate-200 bg-white text-slate-500 hover:text-blue-600'
}`}
>
{index + 1} · {point + 1}
</button>
);
})}
<button
onClick={preloadAllFusionPoints}
className="rounded-lg bg-blue-600 px-2 py-1 text-[10px] font-bold text-white hover:bg-blue-700"
>
</button>
<span className="text-[10px] font-bold text-slate-400">{preloadMessage}</span>
</div>
</div>
</div>

View File

@@ -3,7 +3,6 @@ import { motion } from 'motion/react';
import {
BarChart3,
FolderRoot,
Box,
Workflow,
Settings,
LogOut,
@@ -32,7 +31,6 @@ export default function Sidebar({
const menuItems = [
{ id: ViewType.OVERVIEW, icon: BarChart3, label: '总体概况' },
{ id: ViewType.PROJECTS, icon: FolderRoot, label: '项目库' },
{ id: ViewType.MODELS, icon: Box, label: '模型库' },
{ id: ViewType.WORKSPACE, icon: Workflow, label: '逆向工作区' },
{ id: ViewType.SYSTEM, icon: Settings, label: '系统管理工作区' },
];

View File

@@ -1,7 +1,6 @@
export enum ViewType {
OVERVIEW = 'overview',
PROJECTS = 'projects',
MODELS = 'models',
WORKSPACE = 'workspace',
SYSTEM = 'system',
}