From d63eb1a5afaab0c5defd1715ebf9a2761486dfb0 Mon Sep 17 00:00:00 2001 From: mozzie Date: Mon, 4 Sep 2023 16:34:39 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=97=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/dmp/core/domain/User/UserRepository.ts | 4 + apps/dmp/core/domain/User/UserService.ts | 11 ++- apps/dmp/core/infra/api/Request.ts | 2 +- apps/dmp/core/infra/api/index.ts | 2 + .../Layout/Menu/roleMenu.config.tsx | 46 --------- .../Admin/Dicom/List/TaskTable/index.tsx | 7 -- .../src/modules/Admin/Dicom/List/columns.tsx | 35 +++++++ .../src/modules/Admin/Dicom/List/index.tsx | 94 ++++++++++++++++++- .../src/modules/Admin/Dicom/Upload/index.tsx | 14 ++- apps/dmp/src/modules/Admin/Label/index.tsx | 7 ++ apps/dmp/src/modules/Admin/index.tsx | 2 + apps/dmp/src/router/roleRoutes.tsx | 5 + apps/services/dicom/.env.dev | 4 +- apps/services/dicom/package.json | 3 +- apps/services/dicom/src/app.controller.ts | 51 +++++++++- .../dmp/archive/src/app.controller.ts | 4 +- apps/services/dmp/archive/src/app.service.ts | 25 +++-- .../dmp/gateway/src/admin/admin.controller.ts | 12 ++- pnpm-lock.yaml | 58 ++++-------- 19 files changed, 275 insertions(+), 111 deletions(-) delete mode 100644 apps/dmp/src/components/Layout/Menu/roleMenu.config.tsx delete mode 100644 apps/dmp/src/modules/Admin/Dicom/List/TaskTable/index.tsx create mode 100644 apps/dmp/src/modules/Admin/Dicom/List/columns.tsx create mode 100644 apps/dmp/src/modules/Admin/Label/index.tsx diff --git a/apps/dmp/core/domain/User/UserRepository.ts b/apps/dmp/core/domain/User/UserRepository.ts index ddb9874..43261ba 100644 --- a/apps/dmp/core/domain/User/UserRepository.ts +++ b/apps/dmp/core/domain/User/UserRepository.ts @@ -28,4 +28,8 @@ export class UserRepository { async findArchiveTask() { return await Apis.findArchiveTask(); } + + async findDicoms() { + return await Apis.findDicoms(); + } } diff --git a/apps/dmp/core/domain/User/UserService.ts b/apps/dmp/core/domain/User/UserService.ts index d358d1b..76d6183 100644 --- a/apps/dmp/core/domain/User/UserService.ts +++ b/apps/dmp/core/domain/User/UserService.ts @@ -54,7 +54,12 @@ export class UserService { * 分配标注序列 */ async createArchiveTask(user: User, study: Study[]) { - return await this.userRepository.createArchiveTask({ user, study }); + const { code, data } = await this.userRepository.createArchiveTask({ + user, + study, + }); + const { ignore } = data as { ignore: [] }; + return { code, ignore }; } /** @@ -63,4 +68,8 @@ export class UserService { async findArchiveTask() { return await this.userRepository.findArchiveTask(); } + + async findDicoms(){ + return await this.userRepository.findDicoms() + } } diff --git a/apps/dmp/core/infra/api/Request.ts b/apps/dmp/core/infra/api/Request.ts index 5b83404..bcbc334 100644 --- a/apps/dmp/core/infra/api/Request.ts +++ b/apps/dmp/core/infra/api/Request.ts @@ -104,7 +104,7 @@ class AxiosRequestInstance { public async post( url: string, data?: any, - config?: RequestConfig & { onRequestSent?: RequestCallback } + config?: RequestConfig & { onRequestSent?: RequestCallback } & any ): Promise { const response = await this.instance.post(url, data, config); return response.data; diff --git a/apps/dmp/core/infra/api/index.ts b/apps/dmp/core/infra/api/index.ts index df9677f..52a4583 100644 --- a/apps/dmp/core/infra/api/index.ts +++ b/apps/dmp/core/infra/api/index.ts @@ -78,4 +78,6 @@ export const Apis = { */ findArchiveTask: (): ResponseType => Request.get(PREFIX + "/annotator/find/archiveTask"), + + findDicoms: (): ResponseType => Request.get(PREFIX + "/admin/find/dicom/all"), }; diff --git a/apps/dmp/src/components/Layout/Menu/roleMenu.config.tsx b/apps/dmp/src/components/Layout/Menu/roleMenu.config.tsx deleted file mode 100644 index cad2c15..0000000 --- a/apps/dmp/src/components/Layout/Menu/roleMenu.config.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { ROLE_NAME } from "@/constant"; -import { - CloudUploadOutlined, - DatabaseOutlined, - UnorderedListOutlined, -} from "@ant-design/icons"; -import { MenuProps } from "antd"; - -export type MenuItem = Required["items"][number]; - -const getItem = ( - label: React.ReactNode, - key: React.Key, - icon?: React.ReactNode, - children?: MenuItem[], - type?: "group" -): MenuItem => { - return { - key, - icon, - children, - label, - type, - } as MenuItem; -}; - -const adminMenuItems: MenuItem[] = [ - getItem("影像", "dicom", , [ - getItem("上传", "/upload", ), - getItem("列表", "/list", ), - ]), -]; - -const annotatorMenuItems: MenuItem[] = [ - getItem("影像", "dicom", , [ - getItem("标注", "/list", ), - ]), -]; - -/** - * key对应roles的name字段,创建角色的key - */ -export const roleMenusMapping: Record = { - [ROLE_NAME.ADMIN]: adminMenuItems, - [ROLE_NAME.ANNOTATOR]: annotatorMenuItems, -}; diff --git a/apps/dmp/src/modules/Admin/Dicom/List/TaskTable/index.tsx b/apps/dmp/src/modules/Admin/Dicom/List/TaskTable/index.tsx deleted file mode 100644 index f9553b3..0000000 --- a/apps/dmp/src/modules/Admin/Dicom/List/TaskTable/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -interface ArchiveTaskProps { - children?: JSX.Element; -} - -export const ArchiveTask = (props: ArchiveTaskProps) => { - return
ArchiveTask
-} diff --git a/apps/dmp/src/modules/Admin/Dicom/List/columns.tsx b/apps/dmp/src/modules/Admin/Dicom/List/columns.tsx new file mode 100644 index 0000000..3032a1c --- /dev/null +++ b/apps/dmp/src/modules/Admin/Dicom/List/columns.tsx @@ -0,0 +1,35 @@ +import { TableColumnsType } from "antd"; +import { DataItemType } from "."; + +export const columnsForStudy: TableColumnsType = [ + { title: "PatientID", dataIndex: "PatientID", key: "PatientID" }, + { title: "患者姓名", dataIndex: "PatientName", key: "PatientName" }, + { title: "性别", dataIndex: "PatientSex", key: "PatientSex" }, + { title: "出生日期", dataIndex: "PatientBirthDate", key: "PatientBirthDate" }, + { title: "病例日期", dataIndex: "StudyDate", key: "StudyDate" }, + { + title: "相关序列数", + dataIndex: "NumberPatientRelatedInstances", + key: "NumberPatientRelatedInstances", + }, +]; + +export const columnsForSeries: TableColumnsType = [ + { title: "序列号", dataIndex: "SeriesNumber", key: "SeriesNumber" }, + { + title: "成像设备", + dataIndex: "Modality", + key: "Modality", + }, + { + title: "序列描述", + dataIndex: "SeriesDescription", + key: "SeriesDescription", + }, + + { + title: "切片数", + dataIndex: "NumberSeriesRelatedInstances", + key: "NumberSeriesRelatedInstances", + }, +]; diff --git a/apps/dmp/src/modules/Admin/Dicom/List/index.tsx b/apps/dmp/src/modules/Admin/Dicom/List/index.tsx index 2a7ef1c..d7ea776 100644 --- a/apps/dmp/src/modules/Admin/Dicom/List/index.tsx +++ b/apps/dmp/src/modules/Admin/Dicom/List/index.tsx @@ -1,7 +1,97 @@ +import { useDomain } from "@/hook/useDomain"; +import { Button, Space, Table } from "antd"; +import { useEffect, useState } from "react"; +import { columnsForStudy, columnsForSeries } from "./columns"; +import { EyeOutlined } from "@ant-design/icons"; +import { openOHIFViewer } from "../Upload/util"; + interface DicomListProps { children?: JSX.Element; } -export const DicomList = (props: DicomListProps) => { - return
DicomList
; +export type DataItemType = { + StudyDate: string; + StudyTime: string; + AccessionNumber: string; + Modality: string; + PatientName: string; + PatientID: string; + PatientBirthDate: string; + PatientSex: string; + StudyInstanceUID: string; + SeriesInstanceUID: string; + CharacterSet: string; + SeriesDescription: string; + StudyID: string; + SeriesNumber: string | number; + NumberSeriesRelatedInstances: string | number; + NumberPatientRelatedInstances: string | number; + NumberPatientRelatedSeries: string | number; + subs: DataItemType[]; +}; + +export const DicomList = (props: DicomListProps) => { + const [dataSource, setDataSource] = useState([]); + const [tableLoading, setTableLoading] = useState(false); + const { userDomainService } = useDomain(); + useEffect(() => { + setTableLoading(true); + userDomainService.findDicoms().then((result) => { + const { data } = result; + setDataSource(data as DataItemType[]); + setTableLoading(false); + }); + }, []); + + /** + * 序列级别 + */ + const expandedRowRenderForSeries = (record: DataItemType) => { + return ( + ( + + + + ), + }, + ]} + dataSource={record.subs} + pagination={false} + /> + ); + }; + + const onViewDicom = (record: DataItemType, recordSeries: DataItemType) => { + const { StudyInstanceUID } = record; + const { SeriesInstanceUID } = recordSeries; + openOHIFViewer(StudyInstanceUID, SeriesInstanceUID); + }; + + return ( +
+
+ + ); }; diff --git a/apps/dmp/src/modules/Admin/Dicom/Upload/index.tsx b/apps/dmp/src/modules/Admin/Dicom/Upload/index.tsx index f913e30..e198806 100644 --- a/apps/dmp/src/modules/Admin/Dicom/Upload/index.tsx +++ b/apps/dmp/src/modules/Admin/Dicom/Upload/index.tsx @@ -126,9 +126,19 @@ export const DicomUpload = (props: DicomUploadProps) => { /** * 分配任务 */ - const onAssignConfirm = () => { + const onAssignConfirm = async () => { if (!selectAnnotator?.id) return; - userDomainService.createArchiveTask(selectAnnotator, selectRows); + const { code, ignore } = await userDomainService.createArchiveTask( + selectAnnotator, + selectRows + ); + if (code === 0) { + const info = + ignore?.length > 0 + ? `,其中${ignore.length}条序列,用户${selectAnnotator.username}已存在` + : ``; + message.info(`创建任务成功${info}`); + } setSelectAnnotator(undefined); setIsModalOpen(false); }; diff --git a/apps/dmp/src/modules/Admin/Label/index.tsx b/apps/dmp/src/modules/Admin/Label/index.tsx new file mode 100644 index 0000000..43b3268 --- /dev/null +++ b/apps/dmp/src/modules/Admin/Label/index.tsx @@ -0,0 +1,7 @@ +interface LabelProps { + children?: JSX.Element; +} + +export const Label = (props: LabelProps) => { + return
Label
+} diff --git a/apps/dmp/src/modules/Admin/index.tsx b/apps/dmp/src/modules/Admin/index.tsx index 46a2df2..416ee0f 100644 --- a/apps/dmp/src/modules/Admin/index.tsx +++ b/apps/dmp/src/modules/Admin/index.tsx @@ -3,6 +3,7 @@ import { Layout } from "@/components/Layout"; import { CloudUploadOutlined, DatabaseOutlined, + TagsOutlined, UnorderedListOutlined, } from "@ant-design/icons"; import { Outlet } from "react-router"; @@ -19,6 +20,7 @@ const adminMenuItems: MenuItem[] = [ getItem("上传", "/upload", ), getItem("列表", "/list", ), ]), + getItem("标签", "/label", ), ]; export const AdminDashboard = (props: AdminDashboardProps) => { diff --git a/apps/dmp/src/router/roleRoutes.tsx b/apps/dmp/src/router/roleRoutes.tsx index fd7b33d..13fd624 100644 --- a/apps/dmp/src/router/roleRoutes.tsx +++ b/apps/dmp/src/router/roleRoutes.tsx @@ -6,6 +6,7 @@ import { ExpandRouteProps } from "."; import { ROLE_NAME } from "@/constant"; import { AdminDashboard } from "@/modules/Admin"; import { AnnotatorDashBoard } from "@/modules/Annotator"; +import { Label } from "@/modules/Admin/Label"; export const roleRoutes: Record = { @@ -29,6 +30,10 @@ export const roleRoutes: Record = path: "/upload", element: , }, + { + path: "/label", + element: