const dicomParser = require("dicom-parser"); const BaseController = require("./base"); const fs = require("fs"); const path = require("path"); function getObjectMkdir (url) { let index = url.lastIndexOf("/") let a = url.substring(0,index); return a } function getObjectName (url) { var value = url var str = value.split("/"); //https://进行分割, var name = str[str.length - 1] return name } function parseDicomFile(file, uploadQueues, path) { return new Promise(function(resolve, reject) { try { var data = dicomParser.parseDicom(file) var studyUid = data.string('x0020000d') var studyIndex = 0 while ( studyIndex < uploadQueues.length && uploadQueues[studyIndex].dicomInfo.studyUid !== studyUid ) { ++studyIndex } if (studyIndex >= uploadQueues.length) { var date = data.string('x00080020') var time = data.string('x00080030') var studyTime = '' if (date) { // date = `${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}` date = `${date.substring(0, 4)}-${date.substring(4, 6)}-${date.substring(6, 8)}` } if (time) { time = `${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}` } if(date){ studyTime = time ? `${date} ${time}` : `${date} 00:00:00` } uploadQueues.push({ studyIndex: studyIndex, seriesList: [], fileList: [], dicomInfo: { studyUid: studyUid, patientId: data.string('x00100020'), patientName: data.string('x00100010') ? data.string('x00100010') : '', patientAge: data.string('x00101010') ? data.string('x00101010') : '', patientSex: data.string('x00100040') ? data.string('x00100040') : '', patientBirthDate: data.string('x00100030'), hospitalName: data.string('x00080080'), accNumber: data.string('x00080050'), bodyPart: data.string('x00180015'), modality: [], institutionName: data.string('x00080080'), description: data.string('x00081030'), studyTime: studyTime, VisitInfo: {}, SubjectInfo: {} }, uploadState: { selected: false, stateCode: '', beginUploadTime: {}, progressValue: 0 } }) } var modality = uploadQueues[studyIndex].dicomInfo.modality var currentModality = data.string('x00080060') if (!(modality.indexOf(currentModality) > -1)) { modality.push(currentModality) } var fileList = uploadQueues[studyIndex].fileList var instanceUid = data.string('x00080018') var instanceIndex = 0 while ( instanceIndex < fileList.length && fileList[instanceIndex].instanceUid !== instanceUid ) { ++instanceIndex } if (instanceIndex >= fileList.length) { fileList.push({ instanceUid: instanceUid, file: file }) } var seriesUid = data.string('x0020000e') var seriesList = uploadQueues[studyIndex].seriesList var seriesItem = seriesList.find(function(item) { return item.seriesUid === seriesUid }) if (!seriesItem) { seriesItem = { seriesUid: seriesUid, seriesNumber: data.intString('x00200011') || 1, modality: data.string('x00080060'), description: data.string('x0008103e'), instanceList: [] } seriesList.push(seriesItem) } var instanceList = seriesItem.instanceList var instanceItem = instanceList.find(function(item) { return item.instanceUid === instanceUid }) if (!instanceItem) { instanceItem = { instanceUid: instanceUid, path: path, modality: data.string('x00080060'), instanceNumber: data.intString('x00200013') || 1, frameCount: data.intString('x00280008') || 1, file: file } instanceList.push(instanceItem) } resolve(uploadQueues) } catch (error) { console.log(error) resolve() } }) } class PacsController extends BaseController { constructor(props) { super(props); } //获取pacs位置 async getPACS(){ try{ console.log(this.ctx.request.query) let pacs = await this.ctx.model.Pacs.find(this.ctx.request.query).select("_id aet host port mode description") return this.success(pacs) }catch (error) { return this.error(error) } } async findReading() { try { this.ctx.validate({ trialCode: 'string', subjectCode: 'string', TaskCode: 'string', }) let config = await this.service.config.getConfig(); let a = await this.ctx.service.pacs.findFromPacs(this.ctx.request.body, config) if (a) { let $in = a.map(v => {return v.SeriesInstanceUID}) console.log($in) let list = await this.ctx.model.Series.find({SeriesInstanceUID: {$in: $in}}) // let list = await this.ctx.model.Pacs.find({}) console.log(list) let newA = a.map(v => { let i = list.find(o => { return o.SeriesInstanceUID == v.SeriesInstanceUID }) return { ...v, ...i._doc } }) return this.success(newA) } else { return this.error('找不到影像') } } catch (e) { return this.error(e) } } async pullImage() { try { this.ctx.validate({ pacs_id: 'string', userName: 'string', userId: 'string', task_id: 'string', trialCode: 'string', trialId: 'string', siteId: 'string', subjectId: 'string', subjectVisitId: 'string', subjectCode: 'string', TaskCode: 'string', seriesList: 'array' }) let {pacs_id, seriesList,trialId,siteId,subjectId,subjectVisitId, userName, userId, task_id, trialCode, subjectCode, TaskCode} = this.ctx.request.body let config = await this.service.config.getConfig(); for (let i = 0; i < seriesList.length; i++) { let series = seriesList[i] await this.ctx.service.pacs.movescu(this.ctx.request.body, series, config) await this.ctx.model.Series.findOneAndUpdate({ SeriesInstanceUID: series, }, { $set: { // 拉取中 status: 1, userName: userName, userId: userId } }, {upsert: true, new: true}) } let directoryPath = config.ossPacsPath + `/${trialCode}/${subjectCode}/${TaskCode}/${userId}/` let pathList = fs.readdirSync(directoryPath) let uploadQueues = [] for (let i = 0; i < pathList.length; i++) { let item = path.join(directoryPath, pathList[i]) let file = fs.readFileSync(item) await parseDicomFile(file, uploadQueues, item) } console.log(uploadQueues) const Authorization = this.ctx.get('Authorization'); let arr = [] for (let i = 0; i < uploadQueues.length; ++i) { let info = { trialId: trialId, siteId: siteId, subjectId: subjectId, subjectVisitId: subjectVisitId, fileSize: uploadQueues[i].dicomInfo.fileSize, fileCount: uploadQueues[i].dicomInfo.fileCount, IsDicomReUpload: uploadQueues[i].uploadState.AllowReUpload, visitTaskId: task_id, Authorization: Authorization, } arr.push(this.ctx.service.pacs.archiveStudy(uploadQueues, i ,info, config)) } let a = await Promise.all(arr) // 获取 return this.success(a) } catch (e) { return this.error(e) } } async pushImage() { try{ this.ctx.validate({ pacs_id: 'string', imagesList: 'array', task_id: 'string', trialCode: 'string', subjectCode: 'string', TaskCode: 'string', }) let { pacs_id, imagesList, task_id, trialCode, subjectCode, TaskCode } = this.ctx.request.body let pacs = await this.ctx.model.Pacs.findOne({_id: pacs_id}) let config = await this.service.config.getConfig(); let downloadErrorList = [], downloadsuccessList = [] let studyList = [] for (let i = 0; i < imagesList.length; i++) { let image = imagesList[i] fs.mkdirSync(config.ossPacsPath + getObjectMkdir(`/${trialCode}/${subjectCode}/${TaskCode}/initial_data/1`), { recursive: true }); await this.service.oss.downloadImage(image.InstancePath, `${config.ossPacsPath}/${trialCode}/${subjectCode}/${TaskCode}/initial_data/${getObjectName(image.InstancePath)}`, config) let status_result = await this.ctx.model.Status.findOneAndUpdate({ task_id: task_id }, { $set: { downloadNum: i + 1, status: '下载中', downloadCount: imagesList.length } }, {upsert: true, new: true}) if (!~studyList.indexOf(`${config.ossPacsPath}/${trialCode}/${subjectCode}/${TaskCode}/initial_data`)) { studyList.push(`${config.ossPacsPath}/${trialCode}/${subjectCode}/${TaskCode}/initial_data`) } } console.log(studyList) let status_result = await this.ctx.model.Status.findOneAndUpdate({ task_id: task_id }, { $set: { status: '下载完成', } }, {upsert: true, new: true}) // 开始推送 for (let i = 0; i < studyList.length; i++) { let study = studyList[i] let a = await this.ctx.service.pacs.storescu(pacs, config, study) let status_result = await this.ctx.model.Status.findOneAndUpdate({ task_id: task_id }, { $set: { status: '推送中', } }, {upsert: true, new: true}) } await this.ctx.model.Status.findOneAndUpdate({ task_id: task_id }, { $set: { status: '推送完成', } }, {upsert: true, new: true}) return this.success({downloadErrorList, downloadsuccessList}) }catch (error) { return this.error(error) } } //新增pacs位置 async addPACS(){ try { this.ctx.validate({ trialId: 'string', host: 'string', port: 'string', aet: 'string', }) let { host,port,aet,trialId } = this.ctx.request.body let para = this.ctx.request.body let pacs = await this.ctx.model.Pacs.findOne({ host,port,aet,trialId }) if(pacs){ return this.error("PACS位置已存在",60001) }else{ pacs = this.ctx.model.Pacs(para) let result = await pacs.save() return this.success(result) } } catch (error) { return this.error(error) } } async editPacs() { this.ctx.validate({ trialId: 'string', host: 'string', port: 'string', aet: 'string', }) let { _id, host,port,aet,mode, trialId, description } = this.ctx.request.body let para = this.ctx.request.body let result await this.ctx.model.Pacs.findOneAndUpdate({ _id: _id }, { $set: { // 拉取中 host: host, port: port, aet: aet, mode: mode, description: description } }, {upsert: true, new: true}) return this.success(result) } //删除pacs位置 async delPACS(){ try { this.ctx.validate({ pacs_id: { type: 'string', format: this.config.regexp.objectId } }) let { pacs_id } = this.ctx.request.body let pacs = await this.ctx.model.Pacs.findOne({ _id:pacs_id }); if (!pacs) throw '未找到该PACS' await this.ctx.model.Pacs.deleteOne({ _id:pacs_id }); return this.success() } catch (e) { return this.error(e); } } //测试连接 async testConnection() { try { this.ctx.validate({ pacs_ids:"array" }) } catch (error) { return this.error(error) } try { let { pacs_ids } = this.ctx.request.body if(!pacs_ids.length) return this.error("参数为空") let result = await this.ctx.service.pacs.testConnection(pacs_ids) return this.success(result) } catch (error) { let msg = error if (error.message) { msg = error.message.split('\n') } return this.error(msg) } } async wxFindFromPacs () { try { let { PatientID } = this.ctx.request.body if (!PatientID) { throw 'PatientID必填' } let result = await this.ctx.service.pacs.findFromPacs({PatientID: PatientID}) if (result.length > 0) { let item = result[0] let isHas = await this.ctx.model.Dcmtemp.findOne({StudyInstanceUID: item.StudyInstanceUID}) if (isHas) { this.ctx.model.Dcmtemp.findOneAndUpdate({ _id: isHas._id }, { $set: { host: item.host, port: item.port, aet: item.aet, done: 0, NumberOfStudyRelatedInstances: item.NumberOfStudyRelatedInstances, StudyInstanceUID: item.StudyInstanceUID, status: 0 } }).exec() } else { let params = { host: item.host, port: item.port, aet: item.aet, done: 0, NumberOfStudyRelatedInstances: item.NumberOfStudyRelatedInstances, StudyInstanceUID: item.StudyInstanceUID, status: 0 } let m = new this.ctx.model.Dcmtemp(params) m.save() } } return this.success(result) } catch (error) { let msg = error if (error.message) { msg = error.message.split('\n') } return this.error(msg) } } //查询 async findFromPacs() { try { let result = await this.ctx.service.pacs.findFromPacs(this.ctx.request.body) return this.success(result) } catch (error) { let msg = error if (error.message) { msg = error.message.split('\n') } return this.error(msg) } } //获取下载进度 async percent(){ try { this.ctx.validate({ task_ids:"array" }) } catch (error) { return this.error(error) } let { task_ids } = this.ctx.request.body let result = await this.ctx.model.Status.find({task_id: {$in: task_ids}}) return this.success(result) } //下载 async moveFromPacs() { // 验证数据 try { this.ctx.validate({ para: "array" }) } catch (e) { return this.error(e) } let { para } = this.ctx.request.body try { for (let i = 0; i < para.length; i++) { let item = para[i] let isHas = await this.ctx.model.Dcmtemp.findOne({StudyInstanceUID: item.StudyInstanceUID}) if (isHas) { this.ctx.model.Dcmtemp.findOneAndUpdate({ _id: isHas._id }, { $set: { host: item.host, port: item.port, aet: item.aet, done: 0, NumberOfStudyRelatedInstances: item.NumberOfStudyRelatedInstances, StudyInstanceUID: item.StudyInstanceUID, status: 0 } }).exec() } else { let params = { host: item.host, port: item.port, aet: item.aet, done: 0, NumberOfStudyRelatedInstances: item.NumberOfStudyRelatedInstances, StudyInstanceUID: item.StudyInstanceUID, status: 0 } let m = new this.ctx.model.Dcmtemp(params) m.save() } } return this.success() } catch (error) { return this.error(error) } } //study抽取report async getLocalPort () { return this.success({port: this.config.site.PACS_SCP_PORT, aet: this.config.site.PACS_SCP_AET}) } } module.exports = PacsController;