monorepo-microservice-rbac/apps/dmp/src/modules/Admin/Dicom/Upload/index.tsx
2023-09-01 14:11:16 +08:00

195 lines
6.1 KiB
TypeScript

import { Button, Col, Row, Space, message } from "antd";
import { useDicomUploader } from "./DicomUploader";
import { Series, Study } from "./DicomUploader/util";
import { DicomTable } from "./DicomTable";
import { useDomain } from "@/hook/useDomain";
import { useState } from "react";
import { User } from "@@/domain/User/entities/User";
import { limitConcurrency } from "./limitConcurrency";
import { CloudUploadOutlined, InboxOutlined } from "@ant-design/icons";
import { openOHIFViewer, flatternStudies, FlatStudyItem } from "./util";
import { DicomFileInfo } from "./DicomFileInfo";
import { UploadProgressModal } from "./UploadProgressModal";
import AssignModal from "./AssignModal";
interface DicomUploadProps {
children?: JSX.Element;
}
export const DicomUpload = (props: DicomUploadProps) => {
const [messageApi, contextHolder] = message.useMessage();
const { UploadInput, fileCalculator, studys, isLoading } = useDicomUploader();
const { dicomDomainService, userDomainService } = useDomain();
const { dcmFileNum, totalFileNum, dcmFileSize } = fileCalculator;
const [selectRows, setSelectedRows] = useState<Study[]>([]);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isAssignLoading, setIsAssignLoading] = useState(false);
const [annotators, setAnnotators] = useState<User[]>([]);
const [selectAnnotator, setSelectAnnotator] = useState<User | undefined>(
undefined
);
const [visible, setVisible] = useState<boolean>(false);
const [percent, setPercent] = useState<number>(0);
/**
* 单个序列阅片
*/
const onUploadFiles = async (study: Study, series: Series) => {
const { SeriesInstanceUID, subs } = series;
const { StudyInstanceUID } = study;
const instances = await dicomDomainService.existInPacs({
SeriesInstanceUID,
StudyInstanceUID,
});
// pacs已存在
if (instances.length === subs.length) {
openOHIFViewer(StudyInstanceUID, SeriesInstanceUID);
} else {
setVisible(true);
limitConcurrency(
series.subs.map((f: File) => () => dicomDomainService.upload2Pacs(f)),
10,
(completed, total) => {
console.log(`${completed} out of ${total} tasks completed.`);
setPercent(Math.floor((completed / total) * 100));
},
() => {
setVisible(false);
setPercent(0);
openOHIFViewer(StudyInstanceUID, SeriesInstanceUID);
}
);
}
};
/**
* 返回不在pacs中的影像数据
*/
const filterDicomPromise = () => {
const items = flatternStudies(studys);
// 过滤存在pacs中的序列
const checkExistPromises = items.map(
(item) =>
new Promise(async (resolve) => {
const instances = await dicomDomainService.existInPacs({
SeriesInstanceUID: item.SeriesInstanceUID,
StudyInstanceUID: item.StudyInstanceUID,
});
const existInPacs = instances.length === item.Files.length;
resolve(existInPacs ? false : item);
})
) as Promise<FlatStudyItem | false>[];
return Promise.all(checkExistPromises);
};
/**
* 上传全部
*/
const onUploadEntiredDicom = () => {
// 上传到pacs
filterDicomPromise().then((result) => {
const files = result.map((i) => (!i ? [] : i.Files)).flat();
if (files.length === 0) return messageApi.info("全部影像均已存在pacs中");
setVisible(true);
limitConcurrency(
files.map((f: File) => () => dicomDomainService.upload2Pacs(f)),
10,
(completed, total) => {
console.log(`${completed} out of ${total} tasks completed.`);
setPercent(Math.floor((completed / total) * 100));
},
() => {
setVisible(false);
setPercent(0);
}
);
});
};
const onClickAssign = () => {
// 检查是否全部传到pacs
setIsAssignLoading(true);
filterDicomPromise().then((result) => {
const files = result.map((i) => (!i ? [] : i.Files)).flat();
if (files.length !== 0) {
setIsAssignLoading(false);
return messageApi.info("请先上传全部影像到pacs");
}
userDomainService.getDmpAnnotators().then((res) => {
setIsAssignLoading(false);
setIsModalOpen(true);
setAnnotators(res.data as User[]);
});
});
};
/**
* 分配任务
*/
const onAssignConfirm = () => {
if (!selectAnnotator?.id) return;
userDomainService.createArchiveTask(selectAnnotator, selectRows);
setSelectAnnotator(undefined);
setIsModalOpen(false);
};
return (
<div style={{ padding: 20 }}>
<Row style={{ paddingBottom: 20 }}>
<Col span={24}>
<Space>
<UploadInput />
<Button
icon={<CloudUploadOutlined />}
disabled={Number(dcmFileNum) === 0}
type="primary"
onClick={onUploadEntiredDicom}
>
</Button>
<Button
icon={<InboxOutlined />}
disabled={selectRows.length === 0}
type="primary"
loading={isAssignLoading}
onClick={onClickAssign}
>
</Button>
</Space>
</Col>
</Row>
<DicomFileInfo
dcmFileNum={dcmFileNum}
dcmFileSize={dcmFileSize}
totalFileNum={totalFileNum}
/>
<DicomTable
studys={studys}
loading={isLoading}
onSelectedRows={(rows) => setSelectedRows(rows)}
onUploadFiles={onUploadFiles}
/>
<AssignModal
isOpen={isModalOpen}
options={annotators.map((a) => ({
value: a.id,
label: a.username,
}))}
value={selectAnnotator?.id as number}
onSelectAnnotator={(id: number) =>
setSelectAnnotator(annotators.find((a) => a.id === id))
}
onConfirm={onAssignConfirm}
onCancel={() => setIsModalOpen(false)}
/>
<UploadProgressModal
title="上传影像中"
isOpen={visible}
percent={percent}
/>
{contextHolder}
</div>
);
};