feat: 上传全部影像
This commit is contained in:
parent
976d687b1b
commit
184d84726e
|
@ -54,7 +54,6 @@ export class UserService {
|
||||||
* 分配标注序列
|
* 分配标注序列
|
||||||
*/
|
*/
|
||||||
async createArchiveTask(user: User, study: Study[]) {
|
async createArchiveTask(user: User, study: Study[]) {
|
||||||
console.log(user, study);
|
|
||||||
return await this.userRepository.createArchiveTask({ user, study });
|
return await this.userRepository.createArchiveTask({ user, study });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
43
apps/dmp/src/modules/Admin/Dicom/Upload/AssignModal.tsx
Normal file
43
apps/dmp/src/modules/Admin/Dicom/Upload/AssignModal.tsx
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Modal, Select } from "antd";
|
||||||
|
|
||||||
|
interface AssignModalProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
options: { value: unknown; label: unknown }[];
|
||||||
|
value: number | undefined;
|
||||||
|
onSelectAnnotator: (id: number) => void;
|
||||||
|
onConfirm: () => void;
|
||||||
|
onCancel: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AssignModal: React.FC<AssignModalProps> = ({
|
||||||
|
isOpen,
|
||||||
|
options,
|
||||||
|
value,
|
||||||
|
onSelectAnnotator,
|
||||||
|
onConfirm,
|
||||||
|
onCancel,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
width={320}
|
||||||
|
title="选择标注"
|
||||||
|
open={isOpen}
|
||||||
|
closable
|
||||||
|
cancelText="再想想"
|
||||||
|
okText="确定"
|
||||||
|
onOk={onConfirm}
|
||||||
|
onCancel={onCancel}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
style={{ width: "100%", marginBottom: 20 }}
|
||||||
|
placeholder="选择标注"
|
||||||
|
value={value}
|
||||||
|
onChange={(id) => onSelectAnnotator(id)}
|
||||||
|
options={options}
|
||||||
|
/>
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AssignModal;
|
25
apps/dmp/src/modules/Admin/Dicom/Upload/DicomFileInfo.tsx
Normal file
25
apps/dmp/src/modules/Admin/Dicom/Upload/DicomFileInfo.tsx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { Typography, Space, Divider } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
interface DicomFileInfoProps {
|
||||||
|
totalFileNum: string | number;
|
||||||
|
dcmFileNum: string | number;
|
||||||
|
dcmFileSize: string | number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
export const DicomFileInfo: React.FC<DicomFileInfoProps> = ({
|
||||||
|
totalFileNum,
|
||||||
|
dcmFileNum,
|
||||||
|
dcmFileSize,
|
||||||
|
}) =>
|
||||||
|
!!totalFileNum && (
|
||||||
|
<Space>
|
||||||
|
<Text type="secondary">扫描总文件数: {totalFileNum}</Text>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Text type="secondary">包含: {dcmFileNum} 个dicom文件</Text>
|
||||||
|
<Divider type="vertical" />
|
||||||
|
<Text type="secondary">dcm文件总体积: {dcmFileSize} </Text>
|
||||||
|
</Space>
|
||||||
|
);
|
|
@ -2,60 +2,60 @@ import { TableColumnsType } from "antd";
|
||||||
import { Series, Study } from "../DicomUploader/util";
|
import { Series, Study } from "../DicomUploader/util";
|
||||||
|
|
||||||
export const columnsForStudy: TableColumnsType<Study> = [
|
export const columnsForStudy: TableColumnsType<Study> = [
|
||||||
{ title: "病历号", dataIndex: "patientID", key: "patientID" },
|
{ title: "病历号", dataIndex: "PatientID", key: "PatientID" },
|
||||||
{ title: "姓名", dataIndex: "patientName", key: "patientName" },
|
{ title: "姓名", dataIndex: "PatientName", key: "PatientName" },
|
||||||
{
|
{
|
||||||
title: "序列数",
|
title: "序列数",
|
||||||
key: "seriesNumber",
|
key: "SeriesNumber",
|
||||||
render: (_: any, record: Study) => <span>{record.subs.length}</span>,
|
render: (_: any, record: Study) => <span>{record.subs.length}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "切片数量",
|
title: "切片数量",
|
||||||
key: "seriesNumber",
|
key: "SliceNumber",
|
||||||
render: (_: any, record: Study) => (
|
render: (_: any, record: Study) => (
|
||||||
<span>
|
<span>
|
||||||
{record.subs.map((s) => s.subs.length).reduce((p, n) => p + n)}
|
{record.subs.map((s) => s.subs.length).reduce((p, n) => p + n)}
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{ title: "年龄", dataIndex: "patientAge", key: "patientAge" },
|
{ title: "年龄", dataIndex: "PatientAge", key: "PatientAge" },
|
||||||
{ title: "性别", dataIndex: "patientSex", key: "patientSex" },
|
{ title: "性别", dataIndex: "PatientSex", key: "PatientSex" },
|
||||||
{
|
{
|
||||||
title: "扫描日期",
|
title: "扫描日期",
|
||||||
dataIndex: "acquisitionDate",
|
dataIndex: "AcquisitionDate",
|
||||||
key: "acquisitionDate",
|
key: "AcquisitionDate",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "描述",
|
title: "描述",
|
||||||
dataIndex: "studyDescription",
|
dataIndex: "StudyDescription",
|
||||||
key: "studyDescription",
|
key: "StudyDescription",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
export const columnsForSeries: TableColumnsType<Series> = [
|
export const columnsForSeries: TableColumnsType<Series> = [
|
||||||
{
|
{
|
||||||
title: "序列描述",
|
title: "序列描述",
|
||||||
dataIndex: "seriesDescription",
|
dataIndex: "SeriesDescription",
|
||||||
key: "seriesDescription",
|
key: "SeriesDescription",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "切片数量",
|
title: "切片数量",
|
||||||
key: "sliceNumber",
|
key: "SliceNumber",
|
||||||
render: (_: any, record: Series) => <span>{record.subs.length}</span>,
|
render: (_: any, record: Series) => <span>{record.subs.length}</span>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "切片层厚",
|
title: "切片层厚",
|
||||||
dataIndex: "sliceThickness",
|
dataIndex: "SliceThickness",
|
||||||
key: "sliceThickness",
|
key: "SliceThickness",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "成像设备",
|
title: "成像设备",
|
||||||
dataIndex: "modality",
|
dataIndex: "Modality",
|
||||||
key: "modality",
|
key: "Modality",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "设备制造商",
|
title: "设备制造商",
|
||||||
dataIndex: "manufacturer",
|
dataIndex: "Manufacturer",
|
||||||
key: "manufacturer",
|
key: "Manufacturer",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -2,27 +2,27 @@ import * as dicomParser from "dicom-parser";
|
||||||
|
|
||||||
export interface Series {
|
export interface Series {
|
||||||
SeriesInstanceUID: string;
|
SeriesInstanceUID: string;
|
||||||
sliceThickness: string;
|
SliceThickness: string;
|
||||||
seriesDescription: string;
|
SeriesDescription: string;
|
||||||
/**
|
/**
|
||||||
* 成像设备
|
* 成像设备
|
||||||
*/
|
*/
|
||||||
modality: string;
|
Modality: string;
|
||||||
/**
|
/**
|
||||||
* 设备商
|
* 设备商
|
||||||
*/
|
*/
|
||||||
manufacturer: string;
|
Manufacturer: string;
|
||||||
subs: File[];
|
subs: File[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Study {
|
export interface Study {
|
||||||
StudyInstanceUID: string;
|
StudyInstanceUID: string;
|
||||||
studyDescription: string;
|
StudyDescription: string;
|
||||||
patientID: string;
|
PatientID: string;
|
||||||
patientAge: string;
|
PatientAge: string;
|
||||||
patientName: string;
|
PatientName: string;
|
||||||
patientSex: string;
|
PatientSex: string;
|
||||||
acquisitionDate: string;
|
AcquisitionDate: string;
|
||||||
subs: Series[];
|
subs: Series[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,31 +38,31 @@ export const parseDcmFiles = async (dcmFiles: File[]): Promise<Study[]> => {
|
||||||
const byteArray = new Uint8Array(arrayBuffer);
|
const byteArray = new Uint8Array(arrayBuffer);
|
||||||
const dataSet = dicomParser.parseDicom(byteArray);
|
const dataSet = dicomParser.parseDicom(byteArray);
|
||||||
|
|
||||||
const patientID = dataSet.string("x00100020") ?? "无";
|
const PatientID = dataSet.string("x00100020") ?? "无";
|
||||||
const StudyInstanceUID = dataSet.string("x0020000d");
|
const StudyInstanceUID = dataSet.string("x0020000d");
|
||||||
const studyDescription = dataSet.string("x00081030") ?? "无";
|
const StudyDescription = dataSet.string("x00081030") ?? "无";
|
||||||
const SeriesInstanceUID = dataSet.string("x0020000e");
|
const SeriesInstanceUID = dataSet.string("x0020000e");
|
||||||
const patientName = dataSet.string("x00100010") ?? "无";
|
const PatientName = dataSet.string("x00100010") ?? "无";
|
||||||
const patientSex = dataSet.string("x00100040") ?? "无";
|
const PatientSex = dataSet.string("x00100040") ?? "无";
|
||||||
const patientAge = dataSet.string("x00101010") ?? "无";
|
const PatientAge = dataSet.string("x00101010") ?? "无";
|
||||||
const sliceThickness = dataSet.string("x00180050");
|
const SliceThickness = dataSet.string("x00180050");
|
||||||
const acquisitionDate = dataSet.string("x00080022") ?? "无";
|
const AcquisitionDate = dataSet.string("x00080022") ?? "无";
|
||||||
const seriesDescription = dataSet.string("x0008103e") ?? "无";
|
const SeriesDescription = dataSet.string("x0008103e") ?? "无";
|
||||||
const modality = dataSet.string("x00080060") ?? "无";
|
const Modality = dataSet.string("x00080060") ?? "无";
|
||||||
const manufacturer = dataSet.string("x00081090") ?? "无";
|
const Manufacturer = dataSet.string("x00081090") ?? "无";
|
||||||
|
|
||||||
if (StudyInstanceUID && SeriesInstanceUID && sliceThickness) {
|
if (StudyInstanceUID && SeriesInstanceUID && SliceThickness) {
|
||||||
// 病例级别
|
// 病例级别
|
||||||
let study = studys.find((s) => s.StudyInstanceUID === StudyInstanceUID);
|
let study = studys.find((s) => s.StudyInstanceUID === StudyInstanceUID);
|
||||||
if (!study) {
|
if (!study) {
|
||||||
study = {
|
study = {
|
||||||
StudyInstanceUID,
|
StudyInstanceUID,
|
||||||
studyDescription,
|
StudyDescription,
|
||||||
patientID,
|
PatientID,
|
||||||
patientName,
|
PatientName,
|
||||||
patientSex,
|
PatientSex,
|
||||||
patientAge,
|
PatientAge,
|
||||||
acquisitionDate,
|
AcquisitionDate,
|
||||||
subs: [],
|
subs: [],
|
||||||
};
|
};
|
||||||
studys.push(study);
|
studys.push(study);
|
||||||
|
@ -74,10 +74,10 @@ export const parseDcmFiles = async (dcmFiles: File[]): Promise<Study[]> => {
|
||||||
if (!series) {
|
if (!series) {
|
||||||
series = {
|
series = {
|
||||||
SeriesInstanceUID,
|
SeriesInstanceUID,
|
||||||
sliceThickness,
|
SliceThickness,
|
||||||
seriesDescription,
|
SeriesDescription,
|
||||||
modality,
|
Modality,
|
||||||
manufacturer,
|
Manufacturer,
|
||||||
subs: [],
|
subs: [],
|
||||||
};
|
};
|
||||||
study.subs.push(series);
|
study.subs.push(series);
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from "react";
|
||||||
|
import { Modal, Progress } from "antd";
|
||||||
|
|
||||||
|
interface UploadProgressProps {
|
||||||
|
title: string;
|
||||||
|
isOpen: boolean;
|
||||||
|
percent: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const UploadProgressModal: React.FC<UploadProgressProps> = ({
|
||||||
|
isOpen,
|
||||||
|
percent,
|
||||||
|
title,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Modal title={title} open={isOpen} footer={null} closable={false}>
|
||||||
|
<Progress percent={percent} strokeLinecap="butt" />
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
};
|
|
@ -1,26 +1,16 @@
|
||||||
import {
|
import { Button, Col, Row, Space, message } from "antd";
|
||||||
Button,
|
|
||||||
Col,
|
|
||||||
Divider,
|
|
||||||
Modal,
|
|
||||||
Progress,
|
|
||||||
Row,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
message,
|
|
||||||
} from "antd";
|
|
||||||
import { useDicomUploader } from "./DicomUploader";
|
import { useDicomUploader } from "./DicomUploader";
|
||||||
import { Series, Study } from "./DicomUploader/util";
|
import { Series, Study } from "./DicomUploader/util";
|
||||||
import { DicomTable } from "./DicomTable";
|
import { DicomTable } from "./DicomTable";
|
||||||
import { useDomain } from "@/hook/useDomain";
|
import { useDomain } from "@/hook/useDomain";
|
||||||
import { Typography } from "antd";
|
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { User } from "@@/domain/User/entities/User";
|
import { User } from "@@/domain/User/entities/User";
|
||||||
import { limitConcurrency } from "./limitConcurrency";
|
import { limitConcurrency } from "./limitConcurrency";
|
||||||
import { CloudUploadOutlined, InboxOutlined } from "@ant-design/icons";
|
import { CloudUploadOutlined, InboxOutlined } from "@ant-design/icons";
|
||||||
import { openOHIFViewer, flatternStudies, FlatStudyItem } from "./util";
|
import { openOHIFViewer, flatternStudies, FlatStudyItem } from "./util";
|
||||||
|
import { DicomFileInfo } from "./DicomFileInfo";
|
||||||
const { Text } = Typography;
|
import { UploadProgressModal } from "./UploadProgressModal";
|
||||||
|
import AssignModal from "./AssignModal";
|
||||||
|
|
||||||
interface DicomUploadProps {
|
interface DicomUploadProps {
|
||||||
children?: JSX.Element;
|
children?: JSX.Element;
|
||||||
|
@ -33,6 +23,7 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
const { dcmFileNum, totalFileNum, dcmFileSize } = fileCalculator;
|
const { dcmFileNum, totalFileNum, dcmFileSize } = fileCalculator;
|
||||||
const [selectRows, setSelectedRows] = useState<Study[]>([]);
|
const [selectRows, setSelectedRows] = useState<Study[]>([]);
|
||||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||||
|
const [isAssignLoading, setIsAssignLoading] = useState(false);
|
||||||
const [annotators, setAnnotators] = useState<User[]>([]);
|
const [annotators, setAnnotators] = useState<User[]>([]);
|
||||||
const [selectAnnotator, setSelectAnnotator] = useState<User | undefined>(
|
const [selectAnnotator, setSelectAnnotator] = useState<User | undefined>(
|
||||||
undefined
|
undefined
|
||||||
|
@ -72,9 +63,9 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传全部
|
* 返回不在pacs中的影像数据
|
||||||
*/
|
*/
|
||||||
const onUploadEntiredDicom = () => {
|
const filterDicomPromise = () => {
|
||||||
const items = flatternStudies(studys);
|
const items = flatternStudies(studys);
|
||||||
// 过滤存在pacs中的序列
|
// 过滤存在pacs中的序列
|
||||||
const checkExistPromises = items.map(
|
const checkExistPromises = items.map(
|
||||||
|
@ -88,8 +79,15 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
resolve(existInPacs ? false : item);
|
resolve(existInPacs ? false : item);
|
||||||
})
|
})
|
||||||
) as Promise<FlatStudyItem | false>[];
|
) as Promise<FlatStudyItem | false>[];
|
||||||
|
return Promise.all(checkExistPromises);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 上传全部
|
||||||
|
*/
|
||||||
|
const onUploadEntiredDicom = () => {
|
||||||
// 上传到pacs
|
// 上传到pacs
|
||||||
Promise.all(checkExistPromises).then((result) => {
|
filterDicomPromise().then((result) => {
|
||||||
const files = result.map((i) => (!i ? [] : i.Files)).flat();
|
const files = result.map((i) => (!i ? [] : i.Files)).flat();
|
||||||
if (files.length === 0) return messageApi.info("全部影像均已存在pacs中");
|
if (files.length === 0) return messageApi.info("全部影像均已存在pacs中");
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
|
@ -109,26 +107,22 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickAssign = () => {
|
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) => {
|
userDomainService.getDmpAnnotators().then((res) => {
|
||||||
|
setIsAssignLoading(false);
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
setAnnotators(res.data as User[]);
|
setAnnotators(res.data as User[]);
|
||||||
});
|
});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* 统计信息
|
|
||||||
*/
|
|
||||||
const DicomFileInfo = () =>
|
|
||||||
!!totalFileNum && (
|
|
||||||
<Space>
|
|
||||||
<Text type="secondary">扫描总文件数: {totalFileNum}</Text>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Text type="secondary">包含: {dcmFileNum} 个dicom文件</Text>
|
|
||||||
<Divider type="vertical" />
|
|
||||||
<Text type="secondary">dcm文件总体积: {dcmFileSize} </Text>
|
|
||||||
</Space>
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 分配任务
|
* 分配任务
|
||||||
*/
|
*/
|
||||||
|
@ -157,6 +151,7 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
icon={<InboxOutlined />}
|
icon={<InboxOutlined />}
|
||||||
disabled={selectRows.length === 0}
|
disabled={selectRows.length === 0}
|
||||||
type="primary"
|
type="primary"
|
||||||
|
loading={isAssignLoading}
|
||||||
onClick={onClickAssign}
|
onClick={onClickAssign}
|
||||||
>
|
>
|
||||||
分配
|
分配
|
||||||
|
@ -164,39 +159,35 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<DicomFileInfo />
|
<DicomFileInfo
|
||||||
|
dcmFileNum={dcmFileNum}
|
||||||
|
dcmFileSize={dcmFileSize}
|
||||||
|
totalFileNum={totalFileNum}
|
||||||
|
/>
|
||||||
<DicomTable
|
<DicomTable
|
||||||
studys={studys}
|
studys={studys}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
onSelectedRows={(rows) => setSelectedRows(rows)}
|
onSelectedRows={(rows) => setSelectedRows(rows)}
|
||||||
onUploadFiles={onUploadFiles}
|
onUploadFiles={onUploadFiles}
|
||||||
/>
|
/>
|
||||||
<Modal
|
<AssignModal
|
||||||
width={320}
|
isOpen={isModalOpen}
|
||||||
title="选择标注"
|
|
||||||
open={isModalOpen}
|
|
||||||
closable
|
|
||||||
cancelText="再想想"
|
|
||||||
okText="确定"
|
|
||||||
onOk={onAssignConfirm}
|
|
||||||
onCancel={() => setIsModalOpen(false)}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
style={{ width: "100%", marginBottom: 20 }}
|
|
||||||
placeholder="选择标注"
|
|
||||||
value={selectAnnotator?.id as number}
|
|
||||||
onChange={(id: number) =>
|
|
||||||
setSelectAnnotator(annotators.find((a) => a.id === id))
|
|
||||||
}
|
|
||||||
options={annotators.map((a) => ({
|
options={annotators.map((a) => ({
|
||||||
value: a.id,
|
value: a.id,
|
||||||
label: a.username,
|
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}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
|
||||||
<Modal title="上传影像中" open={visible} footer={null} closable={false}>
|
|
||||||
<Progress percent={percent} strokeLinecap="butt" />
|
|
||||||
</Modal>
|
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -8,8 +8,6 @@ export class AppController {
|
||||||
|
|
||||||
@EventPattern({ cmd: 'archive.task.create' })
|
@EventPattern({ cmd: 'archive.task.create' })
|
||||||
async createArchiveTask(payload) {
|
async createArchiveTask(payload) {
|
||||||
const { annotatorId, study } = payload;
|
return await this.appService.createArchiveTask(payload);
|
||||||
console.log(study);
|
|
||||||
return 123;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { AppService } from './app.service';
|
||||||
import { NacosModule } from './nacos/nacos.module';
|
import { NacosModule } from './nacos/nacos.module';
|
||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
import { ArchiveTask } from './entity/archiveTask';
|
import { ArchiveTask } from './entity/archiveTask.entity';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -19,7 +19,7 @@ import { ArchiveTask } from './entity/archiveTask';
|
||||||
port: 3306,
|
port: 3306,
|
||||||
username: 'root',
|
username: 'root',
|
||||||
password: 'root',
|
password: 'root',
|
||||||
database: 'dicom',
|
database: 'dmp',
|
||||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||||
synchronize: true,
|
synchronize: true,
|
||||||
timezone: 'Asia/Shanghai', // 这里设置了时区
|
timezone: 'Asia/Shanghai', // 这里设置了时区
|
||||||
|
|
|
@ -1,4 +1,32 @@
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
|
import { ArchiveTask } from './entity/archiveTask.entity';
|
||||||
|
import { Repository } from 'typeorm';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AppService {}
|
export class AppService {
|
||||||
|
constructor(
|
||||||
|
@InjectRepository(ArchiveTask)
|
||||||
|
private readonly archiveTaskRepository: Repository<ArchiveTask>,
|
||||||
|
) {}
|
||||||
|
async createArchiveTask(payload) {
|
||||||
|
const { annotatorId, study } = payload;
|
||||||
|
try {
|
||||||
|
for (let i = 0; i < study.length; i++) {
|
||||||
|
const { StudyInstanceUID, PatientID } = study[i];
|
||||||
|
for (let j = 0; j < study[i].subs.length; j++) {
|
||||||
|
const { SeriesInstanceUID } = study[i].subs[j];
|
||||||
|
await this.archiveTaskRepository.save({
|
||||||
|
annotatorId,
|
||||||
|
PatientID,
|
||||||
|
StudyInstanceUID,
|
||||||
|
SeriesInstanceUID,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { success: true };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,9 +3,12 @@ import {
|
||||||
CreateDateColumn,
|
CreateDateColumn,
|
||||||
Entity,
|
Entity,
|
||||||
PrimaryGeneratedColumn,
|
PrimaryGeneratedColumn,
|
||||||
|
Unique,
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from 'typeorm';
|
} from 'typeorm';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
|
@Unique(['annotatorId', 'StudyInstanceUID', 'SeriesInstanceUID'])
|
||||||
export class ArchiveTask {
|
export class ArchiveTask {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -14,7 +17,10 @@ export class ArchiveTask {
|
||||||
annotatorId: number;
|
annotatorId: number;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
StudyInstanceUID;
|
PatientID: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
StudyInstanceUID: string;
|
||||||
|
|
||||||
@Column()
|
@Column()
|
||||||
SeriesInstanceUID: string;
|
SeriesInstanceUID: string;
|
|
@ -17,10 +17,10 @@ export class AdminController {
|
||||||
@Post('createArchiveTask')
|
@Post('createArchiveTask')
|
||||||
async createArchiveTask(@Body() body) {
|
async createArchiveTask(@Body() body) {
|
||||||
const { user, study } = body;
|
const { user, study } = body;
|
||||||
const { annotatorId } = user;
|
const { id: annotatorId } = user;
|
||||||
const { data } = await firstValueFrom(
|
const { success, error } = await firstValueFrom(
|
||||||
this.client.send({ cmd: 'archive.task.create' }, { annotatorId, study }),
|
this.client.send({ cmd: 'archive.task.create' }, { annotatorId, study }),
|
||||||
);
|
);
|
||||||
return { data, code: 0 };
|
return success ? { code: 0 } : { code: 1, msg: error.code };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user