feat: 并发限流上传
This commit is contained in:
parent
063e812448
commit
56f2303fa8
|
@ -4,10 +4,16 @@ import { DicomRepository } from "./DicomRepository";
|
||||||
export class DicomService {
|
export class DicomService {
|
||||||
constructor(private dicomRepository: DicomRepository) {}
|
constructor(private dicomRepository: DicomRepository) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 直穿pacs
|
||||||
|
*/
|
||||||
async upload2Pacs(dcmFile: File) {
|
async upload2Pacs(dcmFile: File) {
|
||||||
return await this.dicomRepository.upload2Pacs(dcmFile);
|
return await this.dicomRepository.upload2Pacs(dcmFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* dicom徐磊是否在pacs中存在
|
||||||
|
*/
|
||||||
async existInPacs(p: ExistInPacsDTO) {
|
async existInPacs(p: ExistInPacsDTO) {
|
||||||
return await this.dicomRepository.existInPacs(p);
|
return await this.dicomRepository.existInPacs(p);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { makeAutoObservable } from "mobx";
|
||||||
import { UserRepository } from "./UserRepository";
|
import { UserRepository } from "./UserRepository";
|
||||||
import { User } from "./entities/User";
|
import { User } from "./entities/User";
|
||||||
import { RouteObject } from "react-router";
|
import { RouteObject } from "react-router";
|
||||||
|
import { Study } from "@/modules/Admin/Dicom/Upload/DicomUploader/util";
|
||||||
|
|
||||||
export class UserService {
|
export class UserService {
|
||||||
user: User;
|
user: User;
|
||||||
|
@ -47,4 +48,11 @@ export class UserService {
|
||||||
async getDmpAnnotators() {
|
async getDmpAnnotators() {
|
||||||
return await this.userRepository.getDmpAnnotators();
|
return await this.userRepository.getDmpAnnotators();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配标注序列
|
||||||
|
*/
|
||||||
|
async assignLabelDicom(user: User, study: Study[]) {
|
||||||
|
console.log(user, study);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { makeAutoObservable } from "mobx";
|
import { makeAutoObservable } from "mobx";
|
||||||
|
|
||||||
interface UserProps {
|
interface UserProps {
|
||||||
id?: number | string;
|
id?: number | string | undefined;
|
||||||
username?: string;
|
username?: string;
|
||||||
password?: string;
|
password?: string;
|
||||||
isEnabled?: boolean;
|
isEnabled?: boolean;
|
||||||
|
|
|
@ -5,6 +5,8 @@ import { DicomTable } from "./DicomTable";
|
||||||
import { useDomain } from "@/hook/useDomain";
|
import { useDomain } from "@/hook/useDomain";
|
||||||
import { Typography } from "antd";
|
import { Typography } from "antd";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import { User } from "@@/domain/User/entities/User";
|
||||||
|
import { limitConcurrency } from "./limitConcurrency";
|
||||||
|
|
||||||
const { Text } = Typography;
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
@ -29,9 +31,9 @@ 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 [annotators, setAnnotators] = useState([]);
|
const [annotators, setAnnotators] = useState<User[]>([]);
|
||||||
const [selectAnnotatorId, setSelectAnnotatorId] = useState<string | number>(
|
const [selectAnnotator, setSelectAnnotator] = useState<User | undefined>(
|
||||||
""
|
undefined
|
||||||
);
|
);
|
||||||
|
|
||||||
const onUploadFiles = async (study: Study, series: Series) => {
|
const onUploadFiles = async (study: Study, series: Series) => {
|
||||||
|
@ -45,31 +47,18 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
if (instances.length === subs.length) {
|
if (instances.length === subs.length) {
|
||||||
openOHIFViewer(StudyInstanceUID, SeriesInstanceUID);
|
openOHIFViewer(StudyInstanceUID, SeriesInstanceUID);
|
||||||
} else {
|
} else {
|
||||||
let fullfilled = 0;
|
const uploadFunc = (f: File) => () => dicomDomainService.upload2Pacs(f);
|
||||||
Promise.all(
|
limitConcurrency(series.subs.map(uploadFunc), 10, (completed, total) => {
|
||||||
series.subs.map((file) =>
|
console.log(`${completed} out of ${total} tasks completed.`);
|
||||||
dicomDomainService.upload2Pacs(file).then((res) => {
|
|
||||||
if (["success", "AlreadyStored"].includes(res.Status)) {
|
|
||||||
fullfilled++;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
).then((res) => {
|
|
||||||
if (res.length === series.subs.length) {
|
|
||||||
openOHIFViewer(StudyInstanceUID, SeriesInstanceUID);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickAssign = () => {
|
const onClickAssign = () => {
|
||||||
userDomainService.getDmpAnnotators().then((res) => {
|
userDomainService.getDmpAnnotators().then((res) => {
|
||||||
console.log(res);
|
|
||||||
const { data } = res;
|
|
||||||
setIsModalOpen(true);
|
setIsModalOpen(true);
|
||||||
setAnnotators(data.map((u) => ({ label: u.username, value: u.id })));
|
setAnnotators(res.data as User[]);
|
||||||
});
|
});
|
||||||
console.log(selectRows);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const dcmFileInfo = !!totalFileNum && (
|
const dcmFileInfo = !!totalFileNum && (
|
||||||
|
@ -82,10 +71,13 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分配任务
|
||||||
|
*/
|
||||||
const onAssignConfirm = () => {
|
const onAssignConfirm = () => {
|
||||||
if (!selectAnnotatorId) return;
|
if (!selectAnnotator?.id) return;
|
||||||
console.log(selectAnnotatorId);
|
userDomainService.assignLabelDicom(selectAnnotator, selectRows);
|
||||||
setSelectAnnotatorId(0);
|
setSelectAnnotator(undefined);
|
||||||
setIsModalOpen(false);
|
setIsModalOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -124,9 +116,15 @@ export const DicomUpload = (props: DicomUploadProps) => {
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
style={{ width: "100%", marginBottom: 20 }}
|
style={{ width: "100%", marginBottom: 20 }}
|
||||||
defaultValue={selectAnnotatorId}
|
placeholder="选择标注"
|
||||||
onChange={(e) => setSelectAnnotatorId(e)}
|
value={selectAnnotator?.id as number}
|
||||||
options={annotators}
|
onChange={(id: number) =>
|
||||||
|
setSelectAnnotator(annotators.find((a) => a.id === id))
|
||||||
|
}
|
||||||
|
options={annotators.map((a) => ({
|
||||||
|
value: a.id,
|
||||||
|
label: a.username,
|
||||||
|
}))}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
51
apps/dmp/src/modules/Admin/Dicom/Upload/limitConcurrency.ts
Normal file
51
apps/dmp/src/modules/Admin/Dicom/Upload/limitConcurrency.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
type PromiseFunction = () => Promise<any>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Promise<Function>} tasks promise请求函数
|
||||||
|
* @param {number} maxConcurrency 最大并发数
|
||||||
|
* @param {} onProgress 完成任务回调
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export async function limitConcurrency(
|
||||||
|
tasks: PromiseFunction[],
|
||||||
|
maxConcurrency: number,
|
||||||
|
onProgress?: (completed: number, total: number) => void
|
||||||
|
): Promise<any[]> {
|
||||||
|
const results: any[] = new Array(tasks.length);
|
||||||
|
let currentIndex = 0;
|
||||||
|
let completedTasks = 0;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
function executeTask() {
|
||||||
|
const index = currentIndex;
|
||||||
|
currentIndex += 1;
|
||||||
|
|
||||||
|
if (index >= tasks.length) {
|
||||||
|
if (results.length === tasks.length) {
|
||||||
|
resolve(results);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = tasks[index];
|
||||||
|
|
||||||
|
task()
|
||||||
|
.then((result) => {
|
||||||
|
results[index] = result;
|
||||||
|
completedTasks++;
|
||||||
|
if (onProgress) {
|
||||||
|
onProgress(completedTasks, tasks.length);
|
||||||
|
}
|
||||||
|
executeTask();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < Math.min(maxConcurrency, tasks.length); i++) {
|
||||||
|
executeTask();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user