2026-05-07-18-42-53 优化可视化工具栏和构件ID联动

This commit is contained in:
2026-05-07 18:55:14 +08:00
parent 796619632b
commit 97edf35bd0
9 changed files with 393 additions and 155 deletions

View File

@@ -21,20 +21,13 @@ import {
Upload
} from 'lucide-react';
import * as THREE from 'three';
import { DicomInfo, DicomPreview, Project } from '../types';
import { DicomInfo, DicomPreview, ModuleStyle, Project } from '../types';
import { api, downloadDicomArchive, downloadMask } from '../lib/api';
type Plane = 'axial' | 'sagittal' | 'coronal';
type DisplayMode = DicomPreview['mode'];
type SolidityLevel = 'standard' | 'fine' | 'ultra' | 'solid';
interface ModuleStyle {
visible: boolean;
color: string;
opacity: number;
partId: number;
}
interface ModelPose {
rotateX: number;
rotateY: number;
@@ -708,6 +701,28 @@ export default function ProjectLibrary({
const sliceTotal = dicomPreview?.total ?? selectedProject?.dicomCount ?? 0;
const selectedSolidity = solidityOptions.find((option) => option.id === solidityLevel) ?? solidityOptions[0];
const makeDefaultModuleStyle = (index: number, fallback?: Partial<ModuleStyle>): ModuleStyle => ({
visible: fallback?.visible ?? true,
color: fallback?.color ?? defaultModuleColors[index % defaultModuleColors.length],
opacity: fallback?.opacity ?? 0.72,
partId: Math.max(1, Math.min(255, Math.round(fallback?.partId ?? index + 1))),
});
const commitModuleStyles = (next: Record<string, ModuleStyle>) => {
setModuleStyles(next);
if (!selectedProject) {
return;
}
api.updateProjectModuleStyles(selectedProject.id, next)
.then((updated) => {
setSelectedProject(updated);
setProjects((items) => items.map((item) => (item.id === updated.id ? updated : item)));
})
.catch((error) => {
setActionMessage(error instanceof Error ? error.message : '构件样式保存失败');
});
};
useEffect(() => {
setViewMode(initialViewMode);
}, [initialViewMode]);
@@ -715,12 +730,7 @@ export default function ProjectLibrary({
useEffect(() => {
const next: Record<string, ModuleStyle> = {};
stlFiles.forEach((fileName, index) => {
next[fileName] = moduleStyles[fileName] ?? {
visible: true,
color: defaultModuleColors[index % defaultModuleColors.length],
opacity: 0.72,
partId: index + 1,
};
next[fileName] = makeDefaultModuleStyle(index, selectedProject?.moduleStyles?.[fileName] ?? moduleStyles[fileName]);
});
setModuleStyles(next);
setSliceIndex(0);
@@ -773,17 +783,15 @@ export default function ProjectLibrary({
}, [sliceIndex, sliceTotal]);
const updateModuleStyle = (fileName: string, partial: Partial<ModuleStyle>) => {
setModuleStyles(prev => ({
...prev,
[fileName]: {
visible: true,
color: '#3b82f6',
opacity: 0.72,
partId: 1,
...(prev[fileName] ?? {}),
const index = Math.max(0, stlFiles.indexOf(fileName));
const next = {
...moduleStyles,
[fileName]: makeDefaultModuleStyle(index, {
...(moduleStyles[fileName] ?? selectedProject?.moduleStyles?.[fileName]),
...partial,
},
}));
}),
};
commitModuleStyles(next);
};
const updateModulePartId = (fileName: string, value: number) => {
@@ -793,18 +801,14 @@ export default function ProjectLibrary({
const toggleAllModules = () => {
const nextVisible = !allModulesVisible;
setModuleStyles(prev => {
const next = { ...prev };
stlFiles.forEach((fileName, index) => {
next[fileName] = {
visible: nextVisible,
color: next[fileName]?.color ?? defaultModuleColors[index % defaultModuleColors.length],
opacity: next[fileName]?.opacity ?? 0.72,
partId: next[fileName]?.partId ?? index + 1,
};
const next = { ...moduleStyles };
stlFiles.forEach((fileName, index) => {
next[fileName] = makeDefaultModuleStyle(index, {
...(next[fileName] ?? selectedProject?.moduleStyles?.[fileName]),
visible: nextVisible,
});
return next;
});
commitModuleStyles(next);
};
const stepSlice = (delta: number) => {
@@ -1290,7 +1294,7 @@ export default function ProjectLibrary({
<div className="rounded-2xl bg-slate-50 border border-slate-100 p-4 space-y-3">
<div className="flex items-center justify-between gap-2">
<p className="text-xs font-bold text-slate-700">姿</p>
<p className="text-xs font-bold text-slate-700">姿</p>
<div className="flex items-center gap-1">
<button
onClick={resetModelRotationPose}