fix: 上传完成内存泄漏

This commit is contained in:
mozzie 2024-09-20 12:30:56 +08:00
parent e5bf5685cf
commit 2cbab89273
9 changed files with 89 additions and 43 deletions

View File

@ -8,12 +8,11 @@ export const registerDicomHandler = () => {
const dia = await dialog.showOpenDialog({ properties: ["openDirectory"] });
if (dia.canceled) return null;
const dcmPaths = await filterDicoms(dia.filePaths[0]);
await uploadFilesInBatches({
uploadFilesInBatches({
filePaths: dcmPaths,
batchSize: 6,
feedback: (d) => event.reply("dicom:upload:detail", d),
});
event.reply("dicom:upload:finished"); // 重新刷新病人列表
});
ipcMain.handle("dicom:select", async () => {

View File

@ -108,11 +108,4 @@ export const uploadFilesInBatches = async ({
totalEndTime - totalStartTime
} ms`
);
return {
totalSuccess,
totalFailed,
totalTime: totalEndTime - totalStartTime,
progress: 100,
};
};

View File

@ -75,7 +75,8 @@
"react-router-dom": "^6.26.0",
"tailwind-merge": "^2.4.0",
"tailwindcss-animate": "^1.0.7",
"zod": "3.23.8"
"zod": "3.23.8",
"mitt": "3.0.1"
},
"devDependencies": {
"@radix-ui/react-icons": "^1.3.0",

View File

@ -28,19 +28,23 @@ import {
} from "@/components/ui/dialog";
import { Progress } from "@/components/ui/progress";
import { RocketIcon } from "@radix-ui/react-icons";
import emitter from "@/lib/events";
interface ScanProgress {
percentage: number;
interface UploadProgress {
progress: number;
totalSuccess: number;
totalFailed: number;
}
const defaultProgress = {
percentage: 0,
};
export const MenuBar = () => {
const { toast } = useToast();
const navigate = useNavigate();
const [progress, setProgress] = useState<ScanProgress>(defaultProgress);
const [uploading, setUploading] = useState<UploadProgress>({
progress: 0,
totalSuccess: 0,
totalFailed: 0,
});
const [inferOption, setInferOption] =
useState<inferDeviceType[]>(inferDevices);
const [importDialogVisible, setImportDialogVisible] = useState(false);
@ -48,9 +52,9 @@ export const MenuBar = () => {
useEffect(() => {
const handleUploadFeedback = (
_event: Electron.IpcRendererEvent,
data: { progress: number; totalSuccess: number; totalFailed: number }
data: UploadProgress
) => {
setProgress({ percentage: data.progress });
setUploading(data);
};
window.ipcRenderer.on("dicom:upload:detail", handleUploadFeedback);
return () => {
@ -59,12 +63,20 @@ export const MenuBar = () => {
}, []);
useEffect(() => {
const visible = ![0, 100].includes(progress.percentage);
setImportDialogVisible(visible);
}, [progress.percentage]);
const p = uploading?.progress;
if (p > 0 && p < 100 && !importDialogVisible) {
setImportDialogVisible(true);
} else if (p === 100 && importDialogVisible) {
setImportDialogVisible(false);
toast({
title: "操作",
description: `导入完成,成功: ${uploading.totalSuccess},失败: ${uploading.totalFailed}`,
});
emitter.emit("datasource:fetch");
}
}, [uploading, importDialogVisible, navigate, toast]);
const handleImportDicom = () => {
navigate("datasource");
window.ipcRenderer.send("dicom:upload");
};
@ -192,9 +204,9 @@ export const MenuBar = () => {
<div className="flex items-center space-x-2">
<Alert>
<RocketIcon className="h-4 w-4" />
<AlertTitle></AlertTitle>
<AlertTitle></AlertTitle>
<AlertDescription>
<Progress value={progress?.percentage} />
<Progress value={uploading.progress} />
</AlertDescription>
</Alert>
</div>

View File

@ -0,0 +1,5 @@
import mitt from "mitt";
const emitter = mitt();
export default emitter;

View File

@ -13,6 +13,7 @@ import { PatientInfo, SeriesInfo } from "./type";
import { PatientList } from "./PatientList";
import { StudyList } from "./StudyList";
import { SeriesList } from "./SeriesList";
import emitter from "@/lib/events";
export const Datasource = () => {
const rawPatientsRef = useRef<PatientInfo[]>([]);
@ -23,24 +24,20 @@ export const Datasource = () => {
const [selectedStudyId, setSelectedStudyId] = useState<string | null>(null);
const navigate = useNavigate();
const fetchPatients = () => {
window.ipcRenderer
.invoke("dicom:select")
.then((patients: PatientInfo[]) => {
console.log(patients);
rawPatientsRef.current = patients;
setPatients(patients);
});
};
useEffect(() => {
fetchPatients();
}, []);
useEffect(() => {
window.ipcRenderer.on("dicom:upload:finished", fetchPatients);
const fetchData = () => {
window.ipcRenderer
.invoke("dicom:select")
.then((patients: PatientInfo[]) => {
console.log("patients", patients);
rawPatientsRef.current = patients;
setPatients(patients);
});
};
fetchData();
emitter.on("datasource:fetch", fetchData);
return () => {
window.ipcRenderer.off("dicom:upload:finished", fetchPatients);
emitter.off("datasource:fetch", fetchData);
};
}, []);

View File

@ -5,9 +5,14 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { ResetIcon } from "@radix-ui/react-icons";
import { MoonIcon, PersonStanding } from "lucide-react";
export const ToolBarMenu = () => {
export interface ToolBarMenuProps {
onToolButtonClick?: (key: string) => void;
}
export const ToolBarMenu = (props: ToolBarMenuProps) => {
return (
<div className="flex gap-x-2">
<TooltipProvider>
@ -34,6 +39,22 @@ export const ToolBarMenu = () => {
</TooltipContent>
</Tooltip>
</TooltipProvider>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
onClick={() => props.onToolButtonClick?.("reset")}
>
<ResetIcon className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">
<p></p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
};

View File

@ -18,6 +18,7 @@ import {
import {
IStackViewport,
IVolumeViewport,
PublicViewportInput,
} from "@cornerstonejs/core/dist/types/types";
import {
@ -253,10 +254,19 @@ export const Viewer = () => {
}
}, [index]);
const onToolMenuClick = (key: string) => {
const engine = renderingEngineRef.current;
if (key === "reset" && engine) {
const viewport = engine.getViewport(viewportIds[0]) as IVolumeViewport;
viewport.resetCamera(true, true, true, true, false);
viewport.render();
}
};
return (
<div className="w-full h-full flex flex-col">
<div className="flex-shrink-0 border-b border-secondary">
<ToolBarMenu />
<ToolBarMenu onToolButtonClick={onToolMenuClick} />
</div>
<div className="flex-grow">
<ResizablePanelGroup direction="horizontal" className="w-full h-full">

View File

@ -151,6 +151,9 @@ importers:
lucide-react:
specifier: ^0.408.0
version: 0.408.0(react@18.3.1)
mitt:
specifier: 3.0.1
version: 3.0.1
node-machine-id:
specifier: 1.1.12
version: 1.1.12
@ -4034,6 +4037,9 @@ packages:
resolution: {integrity: sha512-umcy022ILvb5/3Djuu8LWeqUa8D68JaBzlttKeMWen48SjabqS3iY5w/vzeMzMUNhLDifyhbOwKDSznB1vvrwg==}
engines: {node: '>= 18'}
mitt@3.0.1:
resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
mkdirp-classic@0.5.3:
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
@ -9845,6 +9851,8 @@ snapshots:
minipass: 7.1.2
rimraf: 5.0.10
mitt@3.0.1: {}
mkdirp-classic@0.5.3: {}
mkdirp@1.0.4: {}