1502 lines
54 KiB
Vue
1502 lines
54 KiB
Vue
<template>
|
|
<div>
|
|
<div class="top">
|
|
<span>{{ $t('upload:dicom:title') }}</span>
|
|
<div class="btnBox">
|
|
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
|
|
<div class="form-group">
|
|
<div id="directoryInputWrapper" class="btn btn-link file-input">
|
|
<el-button
|
|
type="primary"
|
|
:disabled="btnLoading"
|
|
:loading="btnLoading"
|
|
size="mini"
|
|
>
|
|
{{ $t('upload:dicom:button:upload') }}
|
|
</el-button>
|
|
<input
|
|
type="file"
|
|
name="file"
|
|
ref="pathClear"
|
|
:disabled="btnLoading"
|
|
webkitdirectory
|
|
multiple
|
|
title=""
|
|
@change="beginScanFiles($event)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
<!--检查列表-->
|
|
<el-table :data="list" style="width: 100%" height="300" :loading="loading">
|
|
<!--受试者-->
|
|
<el-table-column
|
|
prop="SubjectCode"
|
|
:label="$t('upload:dicom:table:subjectCode')"
|
|
/>
|
|
<!--任务名称-->
|
|
<el-table-column
|
|
prop="TaskBlindName"
|
|
:label="$t('upload:dicom:table:taskBlindName')"
|
|
/>
|
|
<!--原始检查数-->
|
|
<el-table-column
|
|
prop="OrginalStudyList"
|
|
:label="$t('upload:dicom:table:orginalStudyListNum')"
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-button
|
|
v-if="
|
|
scope.row.OrginalStudyList &&
|
|
scope.row.OrginalStudyList.length >= 1
|
|
"
|
|
type="text"
|
|
@click="handleOpenDialog(scope.row, 'OrginalStudyList')"
|
|
>
|
|
<span>{{ scope.row.OrginalStudyList.length }}</span>
|
|
</el-button>
|
|
<span v-else>0</span>
|
|
</template>
|
|
</el-table-column>
|
|
<!--后处理检查数-->
|
|
<el-table-column
|
|
prop="UploadStudyList"
|
|
:label="$t('upload:dicom:table:uploadStudyListNum')"
|
|
>
|
|
<template slot-scope="scope">{{
|
|
scope.row.UploadStudyList && Array.isArray(scope.row.UploadStudyList)
|
|
? scope.row.UploadStudyList.length
|
|
: 0
|
|
}}</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('common:action:action')"
|
|
fixed="right"
|
|
width="180"
|
|
>
|
|
<template slot-scope="scope">
|
|
<div class="btnBox">
|
|
<!--上传--->
|
|
<form
|
|
id="inputForm"
|
|
:ref="`uploadForm_${scope.row.Id}`"
|
|
enctype="multipart/form-data"
|
|
>
|
|
<div class="form-group" style="margin-right: 10px">
|
|
<div
|
|
:id="`directoryInputWrapper_${scope.row.Id}`"
|
|
class="btn btn-link file-input"
|
|
>
|
|
<el-button
|
|
circle
|
|
icon="el-icon-upload2"
|
|
:disabled="btnLoading"
|
|
:loading="btnLoading"
|
|
:title="$t('upload:dicom:button:upload')"
|
|
/>
|
|
<input
|
|
type="file"
|
|
:name="`file_${scope.row.Id}`"
|
|
:ref="`pathClear_${scope.row.Id}`"
|
|
:disabled="btnLoading"
|
|
webkitdirectory
|
|
multiple
|
|
title=""
|
|
@change="
|
|
($event) => beginScanFiles($event, scope.row.VisitTaskId)
|
|
"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
<!--预览--->
|
|
<el-button
|
|
circle
|
|
icon="el-icon-view"
|
|
:disabled="
|
|
!scope.row.UploadStudyList ||
|
|
scope.row.UploadStudyList.length <= 0
|
|
"
|
|
@click.stop="handleViewReadingImages(scope.row)"
|
|
:title="$t('upload:dicom:button:preview')"
|
|
/>
|
|
<!--删除--->
|
|
<el-button
|
|
circle
|
|
:disabled="
|
|
!scope.row.UploadStudyList ||
|
|
scope.row.UploadStudyList.length <= 0
|
|
"
|
|
icon="el-icon-delete"
|
|
:title="$t('upload:dicom:button:delete')"
|
|
@click.stop="remove(scope.row)"
|
|
/>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<div style="margin: 10px 0">
|
|
<span>{{ $t('upload:dicom:uploadTitle') }}</span>
|
|
<span style="margin-left: 10px">{{ $store.state.trials.uploadTip }}</span>
|
|
</div>
|
|
<!--上传列表-->
|
|
<el-table
|
|
ref="dicomFilesTable"
|
|
v-adaptive="{ bottomOffset: 80 }"
|
|
height="100"
|
|
:data="uploadQueues"
|
|
class="dicomFiles-table"
|
|
@selection-change="handleSelectionChange"
|
|
>
|
|
<el-table-column type="index" width="40" />
|
|
<el-table-column min-width="200" show-overflow-tooltip>
|
|
<template slot="header">
|
|
<el-tooltip placement="top">
|
|
<div slot="content">
|
|
{{ $t('trials:uploadDicomList:table:studyDetail1') }}<br />
|
|
{{ $t('trials:uploadDicomList:table:studyDetail2') }}<br />
|
|
{{ $t('trials:uploadedDicoms:table:studyDate') }}
|
|
</div>
|
|
<span>{{ $t('trials:uploadDicomList:table:studyInfo') }}</span>
|
|
</el-tooltip>
|
|
</template>
|
|
<template slot-scope="scope">
|
|
<div style="line-height: 15px">
|
|
<div>
|
|
<div>
|
|
<span v-if="scope.row.dicomInfo.accNumber"
|
|
><span style="font-weight: 500">Acc:</span>
|
|
{{ scope.row.dicomInfo.accNumber }}</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A</span>
|
|
</div>
|
|
<div style="display: inline-block; margin-right: 2px">
|
|
<span v-if="scope.row.dicomInfo.modality.length > 0">
|
|
{{ scope.row.dicomInfo.modality.join('、') }},</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A,</span>
|
|
</div>
|
|
<div style="display: inline-block; margin-right: 2px">
|
|
<span v-if="scope.row.seriesList.length"
|
|
>{{ scope.row.seriesList.length }} Series,</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A,</span>
|
|
</div>
|
|
<div style="display: inline-block">
|
|
<span v-if="scope.row.fileList.length"
|
|
>{{ scope.row.fileList.length }} Instances</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<div style="display: inline-block; margin-right: 2px">
|
|
<span v-if="scope.row.dicomInfo.bodyPart">
|
|
{{ scope.row.dicomInfo.bodyPart }},
|
|
</span>
|
|
<span v-else style="color: #f44336">N/A, </span>
|
|
</div>
|
|
<div style="display: inline-block">
|
|
<span v-if="scope.row.dicomInfo.description">
|
|
{{ scope.row.dicomInfo.description }}</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
{{ scope.row.dicomInfo.studyTime }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column min-width="130" show-overflow-tooltip>
|
|
<template slot="header">
|
|
<el-tooltip placement="top">
|
|
<div slot="content">
|
|
{{ $t('trials:uploadDicomList:table:pId') }}<br />
|
|
{{ $t('trials:uploadDicomList:table:patientName') }}<br />
|
|
{{ $t('trials:uploadDicomList:table:pInfo') }}
|
|
</div>
|
|
<span>{{ $t('trials:uploadDicomList:table:patientInfo') }}</span>
|
|
</el-tooltip>
|
|
</template>
|
|
<template slot-scope="scope">
|
|
<div style="line-height: 15px">
|
|
<div>
|
|
<span v-if="scope.row.dicomInfo.patientId"
|
|
><span style="font-weight: 500">PID: </span
|
|
>{{ scope.row.dicomInfo.patientId }}</span
|
|
>
|
|
<span v-else style="color: #f44336">N/A</span>
|
|
</div>
|
|
<div>
|
|
<span
|
|
:class="[scope.row.dicomInfo.patientName ? '' : 'colorOfRed']"
|
|
>
|
|
{{
|
|
scope.row.dicomInfo.patientName
|
|
? scope.row.dicomInfo.patientName
|
|
: 'N/A'
|
|
}}
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<span
|
|
:class="[scope.row.dicomInfo.patientSex ? '' : 'colorOfRed']"
|
|
>
|
|
{{
|
|
scope.row.dicomInfo.patientSex
|
|
? scope.row.dicomInfo.patientSex
|
|
: 'N/A'
|
|
}},
|
|
</span>
|
|
|
|
<span
|
|
:class="[scope.row.dicomInfo.patientAge ? '' : 'colorOfRed']"
|
|
>
|
|
{{
|
|
scope.row.dicomInfo.patientAge
|
|
? scope.row.dicomInfo.patientAge
|
|
: 'N/A'
|
|
}},
|
|
</span>
|
|
|
|
<span
|
|
:class="[
|
|
scope.row.dicomInfo.patientBirthDate ? '' : 'colorOfRed',
|
|
]"
|
|
>
|
|
{{
|
|
scope.row.dicomInfo.patientBirthDate
|
|
? scope.row.dicomInfo.patientBirthDate
|
|
: 'N/A'
|
|
}}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('trials:uploadDicomList:table:failedFileCount')"
|
|
min-width="150"
|
|
show-overflow-tooltip
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-progress
|
|
color="#409eff"
|
|
:percentage="
|
|
(
|
|
(scope.row.dicomInfo.uploadFileSize * 100) /
|
|
scope.row.dicomInfo.fileSize
|
|
).toFixed(2) * 1
|
|
"
|
|
/>
|
|
<span>
|
|
{{ $t('trials:uploadDicomList:table:uploadNow')
|
|
}}{{ scope.row.dicomInfo.failedFileCount }} /
|
|
{{ scope.row.dicomInfo.fileCount }}: [{{
|
|
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(2)
|
|
}}MB/{{
|
|
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(2)
|
|
}}MB]
|
|
</span>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
<el-table-column
|
|
:label="$t('trials:uploadDicomList:table:status')"
|
|
min-width="140"
|
|
show-overflow-tooltip
|
|
>
|
|
<template slot-scope="scope">
|
|
<span
|
|
v-if="
|
|
!scope.row.dicomInfo.failedFileCount &&
|
|
!scope.row.dicomInfo.isInit
|
|
"
|
|
>
|
|
{{ $t('trials:uploadDicomList:table:status1') }}</span
|
|
>
|
|
<span
|
|
style="color: #409eff"
|
|
v-else-if="
|
|
!scope.row.dicomInfo.failedFileCount &&
|
|
scope.row.dicomInfo.isInit &&
|
|
btnLoading
|
|
"
|
|
>{{ $t('trials:uploadDicomList:table:status2') }}</span
|
|
>
|
|
<span
|
|
style="color: #409eff"
|
|
v-else-if="
|
|
scope.row.dicomInfo.failedFileCount <
|
|
scope.row.dicomInfo.fileCount && !scope.row.uploadState.record
|
|
"
|
|
>{{ $t('trials:uploadDicomList:table:status2') }}</span
|
|
>
|
|
<span
|
|
style="color: #2cc368"
|
|
v-else-if="
|
|
scope.row.dicomInfo.failedFileCount ===
|
|
scope.row.dicomInfo.fileCount
|
|
"
|
|
>{{ $t('trials:uploadDicomList:table:status3') }}</span
|
|
>
|
|
<span
|
|
style="color: #f66"
|
|
v-else-if="
|
|
scope.row.uploadState.record &&
|
|
scope.row.uploadState.record.fileCount === 0
|
|
"
|
|
>{{ $t('trials:uploadDicomList:table:status5') }}</span
|
|
>
|
|
<span style="color: #f66" v-else>{{
|
|
$t('trials:uploadDicomList:table:Failed')
|
|
}}</span>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
:label="$t('trials:uploadDicomList:table:record')"
|
|
min-width="140"
|
|
show-overflow-tooltip
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-tooltip placement="top" v-if="scope.row.uploadState.record">
|
|
<div slot="content">
|
|
<div style="max-height: 500px; overflow-y: auto">
|
|
{{ $t('trials:uploadDicomList:table:Existed') }}:
|
|
<div v-if="scope.row.uploadState.record.Existed.length">
|
|
<div
|
|
v-for="item of scope.row.uploadState.record.Existed"
|
|
:key="item"
|
|
style="font-size: 12px; color: #baa72a"
|
|
>
|
|
{{ item }}
|
|
</div>
|
|
</div>
|
|
<div v-else> </div>
|
|
{{ $t('trials:uploadDicomList:table:Uploaded') }}:
|
|
<div v-if="scope.row.uploadState.record.Uploaded.length">
|
|
<div
|
|
v-for="item of scope.row.uploadState.record.Uploaded"
|
|
:key="item"
|
|
style="font-size: 12px; color: #24b837"
|
|
>
|
|
{{ item }}
|
|
</div>
|
|
</div>
|
|
<div v-else> </div>
|
|
<br />
|
|
{{ $t('trials:uploadDicomList:table:Failed') }}:
|
|
<div v-if="scope.row.uploadState.record.Failed.length">
|
|
<div
|
|
v-for="item of scope.row.uploadState.record.Failed"
|
|
:key="item"
|
|
style="font-size: 12px; color: #f66"
|
|
>
|
|
{{ item }}
|
|
</div>
|
|
</div>
|
|
<div v-else> </div>
|
|
</div>
|
|
</div>
|
|
<el-button size="mini" style="cursor: pointer">
|
|
<span style="font-size: 12px; color: #baa72a">{{
|
|
scope.row.uploadState.record.Existed.length
|
|
}}</span>
|
|
/
|
|
<span style="font-size: 12px; color: #24b837">{{
|
|
scope.row.uploadState.record.Uploaded.length
|
|
}}</span>
|
|
/
|
|
<span style="font-size: 12px; color: #f66">{{
|
|
scope.row.uploadState.record.Failed.length
|
|
}}</span>
|
|
</el-button>
|
|
</el-tooltip>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
<study-view
|
|
v-if="model_cfg.visible"
|
|
:model_cfg="model_cfg"
|
|
:IsDicom="true"
|
|
:modelList="modelList"
|
|
/>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import { dicomUploadInProgress } from '@/api/trials'
|
|
import {
|
|
preArchiveDicomStudy,
|
|
addOrUpdateArchiveTaskStudy,
|
|
} from '@/api/load.js'
|
|
import studyView from './study-view.vue'
|
|
import {
|
|
getSubjectImageUploadList,
|
|
deleteTaskStudy,
|
|
verifyIRStudyAllowUpload,
|
|
} from '@/api/load.js'
|
|
import * as dicomParser from 'dicom-parser'
|
|
import * as cornerstone from 'cornerstone-core'
|
|
import * as cornerstoneWADOImageLoader from 'cornerstone-wado-image-loader'
|
|
var config = {
|
|
maxWebWorkers: 4,
|
|
startWebWorkersOnDemand: true,
|
|
taskConfiguration: {
|
|
decodeTask: {
|
|
initializeCodecsOnStartup: false,
|
|
},
|
|
},
|
|
}
|
|
cornerstoneWADOImageLoader.webWorkerManager.initialize(config)
|
|
cornerstoneWADOImageLoader.external.dicomParser = dicomParser
|
|
cornerstoneWADOImageLoader.external.cornerstone = cornerstone
|
|
import { convertBytes } from '@/utils/dicom-character-set'
|
|
import { parseDicom } from '@/utils/parseDicom.js'
|
|
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
|
|
import store from '@/store'
|
|
import { getToken } from '@/utils/auth'
|
|
export default {
|
|
name: 'dicomFile',
|
|
props: {
|
|
SubjectId: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
SubjectCode: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
Criterion: {
|
|
type: Object,
|
|
default: () => {
|
|
return {}
|
|
},
|
|
},
|
|
},
|
|
components: {
|
|
'study-view': studyView,
|
|
},
|
|
data() {
|
|
return {
|
|
list: [],
|
|
StudyInstanceUidList: [],
|
|
SopInstanceUidList: [],
|
|
UploadStudyList: [],
|
|
// 检查数弹框
|
|
model_cfg: {
|
|
visible: false,
|
|
showClose: true,
|
|
width: '1000px',
|
|
title: '',
|
|
appendToBody: true,
|
|
},
|
|
modelList: [],
|
|
|
|
VisitTaskId: null,
|
|
hasOtherStudy: false,
|
|
|
|
scanState: '', // 当前上传队列上传状态
|
|
form: {
|
|
SiteName: '',
|
|
SubjectName: '',
|
|
VisitName: '',
|
|
SubjectId: '',
|
|
VisitNum: null,
|
|
},
|
|
isScan: false,
|
|
uploadQueues: [], // 上传队列
|
|
studyErrorList: [],
|
|
warningArr: [],
|
|
selectArr: [],
|
|
btnLoading: false,
|
|
myInterval: [],
|
|
isClose: false,
|
|
trialId: null,
|
|
subjectVisitId: null,
|
|
errStudyUidList: [],
|
|
open: null,
|
|
}
|
|
},
|
|
created() {
|
|
this.getList()
|
|
},
|
|
async mounted() {
|
|
this.trialId = this.$route.query.trialId
|
|
this.uploadQueues = []
|
|
this.OSSclient.close()
|
|
},
|
|
beforeDestroy() {
|
|
this.myInterval.forEach((v) => {
|
|
clearInterval(v)
|
|
})
|
|
this.myInterval = []
|
|
store.dispatch('trials/setUnLock', false)
|
|
this.isClose = true
|
|
this.OSSclient.close()
|
|
},
|
|
methods: {
|
|
// 获取列表
|
|
async getList() {
|
|
try {
|
|
let params = {
|
|
SubjectId: this.SubjectId,
|
|
TrialReadingCriterionId: this.Criterion.TrialReadingCriterionId,
|
|
SubjectCode: this.SubjectCode,
|
|
}
|
|
this.loading = true
|
|
let res = await getSubjectImageUploadList(params)
|
|
this.loading = false
|
|
if (res.IsSuccess) {
|
|
this.StudyInstanceUidList = []
|
|
this.SopInstanceUidList = []
|
|
this.UploadStudyList = []
|
|
this.list = res.Result
|
|
res.Result.forEach((item) => {
|
|
if (item.OrginalStudyList && Array.isArray(item.OrginalStudyList)) {
|
|
item.OrginalStudyList.forEach((data) => {
|
|
data.SubjectId = item.SubejctId
|
|
data.VisitTaskId = item.VisitTaskId
|
|
data.SourceSubjectVisitId = item.SourceSubjectVisitId
|
|
this.subjectVisitId = item.SourceSubjectVisitId
|
|
this.StudyInstanceUidList.push(data)
|
|
})
|
|
}
|
|
if (item.UploadStudyList && Array.isArray(item.UploadStudyList)) {
|
|
item.UploadStudyList.forEach((data) => {
|
|
data.SopInstanceUidList &&
|
|
this.SopInstanceUidList.push(...data.SopInstanceUidList)
|
|
data.VisitTaskId = item.VisitTaskId
|
|
this.UploadStudyList.push(data)
|
|
})
|
|
}
|
|
})
|
|
}
|
|
} catch (err) {
|
|
console.log(err)
|
|
this.loading = false
|
|
}
|
|
},
|
|
// 删除
|
|
async remove(item) {
|
|
try {
|
|
let confirm = await this.$confirm(
|
|
this.$t('trials:uploadImage:confirm:delMessage'),
|
|
{
|
|
type: 'warning',
|
|
distinguishCancelAndClose: true,
|
|
confirmButtonText: this.$t('common:button:confirm'),
|
|
cancelButtonText: this.$t('common:button:cancel'),
|
|
}
|
|
)
|
|
if (confirm !== 'confirm') return
|
|
let params = {
|
|
VisitTaskId: item.VisitTaskId,
|
|
IsDicom: true,
|
|
}
|
|
let res = await deleteTaskStudy(params)
|
|
if (res.IsSuccess) {
|
|
this.getList()
|
|
this.$message.success(
|
|
this.$t('trials:uploadImage:message:delSuccess')
|
|
)
|
|
}
|
|
} catch (err) {
|
|
console.log(err)
|
|
}
|
|
},
|
|
// 当选择项发生变化时收集待上传文件数据
|
|
handleSelectionChange(selection) {
|
|
selection.sort((n1, n2) => {
|
|
return n1.studyIndex - n2.studyIndex
|
|
})
|
|
this.selectArr = selection
|
|
},
|
|
// 根据是否上传状态决定CheckBox 是否可以勾选
|
|
handleSelectable(row) {
|
|
if (row.uploadState.selected || this.btnLoading) {
|
|
return false
|
|
} else {
|
|
return true
|
|
}
|
|
},
|
|
// 打开弹窗
|
|
handleOpenDialog(item, list) {
|
|
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.TaskBlindName}`
|
|
this.modelList = item[list]
|
|
this.model_cfg.visible = true
|
|
},
|
|
// 校验上传数据
|
|
async verifyIRStudyAllowUpload(list) {
|
|
try {
|
|
let data = {
|
|
StudyInstanceUidList: list || [],
|
|
TrialId: this.$route.query.trialId,
|
|
SubjectCode: this.SubjectCode,
|
|
SubjectId: this.SubjectId,
|
|
}
|
|
let res = await verifyIRStudyAllowUpload(data)
|
|
if (res.IsSuccess) {
|
|
return res.Result
|
|
}
|
|
return false
|
|
} catch (err) {
|
|
console.log(err)
|
|
return false
|
|
}
|
|
},
|
|
// 扫描待上传文件
|
|
async beginScanFiles(e, id = null) {
|
|
this.VisitTaskId = id
|
|
this.hasOtherStudy = false
|
|
var files = e.target.files
|
|
if (files.length > 0) {
|
|
var checkFiles = [...files]
|
|
let max = checkFiles.some((item) => item.size > 20 * 1024 * 1024 * 1024)
|
|
if (max)
|
|
return this.$message.warning(
|
|
this.$t('trials:uploadDicomList:message:maxFileSize')
|
|
)
|
|
let StudyInstanceUidList = []
|
|
for (let i = 0; i < checkFiles.length; i++) {
|
|
let item = checkFiles[i]
|
|
var dicom = await parseDicom(item, 'StudyInstanceUid')
|
|
let has = true,
|
|
has2 = false,
|
|
has3 = false
|
|
if (!this.VisitTaskId) {
|
|
has = this.StudyInstanceUidList.some(
|
|
(item) => item.StudyInstanceUid === dicom.StudyInstanceUid
|
|
)
|
|
} else {
|
|
has2 = this.StudyInstanceUidList.some((item) => {
|
|
return (
|
|
item.StudyInstanceUid === dicom.StudyInstanceUid &&
|
|
item.VisitTaskId !== this.VisitTaskId
|
|
)
|
|
})
|
|
has3 = this.UploadStudyList.some((item) => {
|
|
return (
|
|
item.StudyInstanceUid === dicom.StudyInstanceUid &&
|
|
item.VisitTaskId !== this.VisitTaskId
|
|
)
|
|
})
|
|
}
|
|
|
|
if (!has || has2 || has3) {
|
|
this.hasOtherStudy = true
|
|
checkFiles.splice(i, 1)
|
|
i--
|
|
} else {
|
|
if (!~StudyInstanceUidList.indexOf(dicom.StudyInstanceUid)) {
|
|
StudyInstanceUidList.push(dicom.StudyInstanceUid)
|
|
}
|
|
}
|
|
}
|
|
this.errStudyUidList = []
|
|
let res = await this.verifyIRStudyAllowUpload(StudyInstanceUidList)
|
|
if (res) {
|
|
res.forEach((item) => {
|
|
if (!item.IsAllowUpload && !item.IsAllowReUpload) {
|
|
this.errStudyUidList.push(item.StudyInstanceUid)
|
|
}
|
|
})
|
|
}
|
|
if (this.errStudyUidList && this.errStudyUidList.length > 0) {
|
|
for (let i = 0; i < checkFiles.length; i++) {
|
|
let item = checkFiles[i]
|
|
var dicom = await parseDicom(item, 'StudyInstanceUid')
|
|
if (!!~this.errStudyUidList.indexOf(dicom.StudyInstanceUid)) {
|
|
this.hasOtherStudy = true
|
|
checkFiles.splice(i, 1)
|
|
i--
|
|
}
|
|
}
|
|
}
|
|
if (this.hasOtherStudy) {
|
|
this.$confirm(this.$t('upload:dicom:confirmMessage:hasNotStudyUid'), {
|
|
type: 'warning',
|
|
distinguishCancelAndClose: true,
|
|
confirmButtonText: this.$t('common:button:confirm'),
|
|
cancelButtonText: this.$t('common:button:cancel'),
|
|
})
|
|
}
|
|
|
|
var scope = this
|
|
scope.scanState = ''
|
|
scope.isScan = false
|
|
var p = new Promise(function (resolve) {
|
|
resolve()
|
|
})
|
|
var validFilesCount = 0
|
|
for (var i = 0; i < checkFiles.length; ++i) {
|
|
;(function (index) {
|
|
p = p.then(function () {
|
|
if (
|
|
checkFiles[index].name.toUpperCase().indexOf('DICOMDIR') === -1
|
|
) {
|
|
validFilesCount = validFilesCount + 1
|
|
return scope.parseDicomFile(checkFiles[index])
|
|
}
|
|
})
|
|
})(i)
|
|
}
|
|
p.then(function (result) {
|
|
scope.uploadQueues.forEach((v, i) => {
|
|
scope.$refs.dicomFilesTable.toggleRowSelection(v, true)
|
|
})
|
|
scope.scanState = 'finished'
|
|
scope.isScan = true
|
|
scope.beginUploadQueues()
|
|
})
|
|
}
|
|
},
|
|
// 按序列UUID本地归档
|
|
parseDicomFile(file) {
|
|
var scope = this
|
|
return new Promise(function (resolve, reject) {
|
|
if (scope.scanState === 'cancelling') {
|
|
resolve()
|
|
return
|
|
}
|
|
var reader = new FileReader()
|
|
reader.onload = function (e) {
|
|
try {
|
|
var data = dicomParser.parseDicom(new Uint8Array(e.target.result))
|
|
var instanceUid = data.string('x00080018')
|
|
if (!instanceUid) return resolve()
|
|
var modality = data.string('x00080060') || ''
|
|
var studyUid = data.string('x0020000d')
|
|
if (!studyUid) return resolve()
|
|
var pixelDataElement = data.elements.x7fe00010
|
|
var studyIndex = 0
|
|
while (
|
|
studyIndex < scope.uploadQueues.length &&
|
|
scope.uploadQueues[studyIndex].dicomInfo.studyUid !== studyUid &&
|
|
(pixelDataElement || modality === 'SR') &&
|
|
modality != ''
|
|
) {
|
|
++studyIndex
|
|
}
|
|
if (studyIndex >= scope.uploadQueues.length) {
|
|
var date = data.string('x00080020')
|
|
var time = data.string('x00080030')
|
|
var studyTime = ''
|
|
if (date) {
|
|
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`
|
|
}
|
|
const patientNameElement = data.elements.x00100010
|
|
const patientNameBytes = new Uint8Array(
|
|
data.byteArray.buffer,
|
|
patientNameElement ? patientNameElement.dataOffset : 0,
|
|
patientNameElement ? patientNameElement.length : 0
|
|
)
|
|
const patientNameStr = convertBytes(
|
|
data.string('x00080005'),
|
|
patientNameBytes
|
|
)
|
|
scope.uploadQueues.push({
|
|
studyIndex: studyIndex,
|
|
seriesList: [],
|
|
fileList: [],
|
|
dicomInfo: {
|
|
studyId: data.string('x00200010'),
|
|
studyUid: studyUid,
|
|
patientId: data.string('x00100020'),
|
|
patientName: patientNameStr,
|
|
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'),
|
|
//0008,0032
|
|
acquisitionTime: data.string('x00080032'),
|
|
acquisitionNumber: data.string('x00200012'),
|
|
triggerTime: data.string('x00181060'),
|
|
studyTime: studyTime,
|
|
VisitInfo: {},
|
|
SubjectInfo: {},
|
|
failedFileCount: 0,
|
|
uploadFileSize: 0,
|
|
fileSize: 0,
|
|
fileCount: 0,
|
|
isInit: false,
|
|
visitTaskId:
|
|
scope.VisitTaskId ||
|
|
scope.StudyInstanceUidList.find(
|
|
(item) => item.studyInstanceUid === studyUid
|
|
).VisitTaskId,
|
|
},
|
|
|
|
uploadState: {
|
|
selected: false,
|
|
stateCode: '',
|
|
beginUploadTime: {},
|
|
progressValue: 0,
|
|
},
|
|
})
|
|
}
|
|
var modality = scope.uploadQueues[studyIndex].dicomInfo.modality
|
|
var currentModality = data.string('x00080060')
|
|
if (!(modality.indexOf(currentModality) > -1)) {
|
|
modality.push(currentModality)
|
|
}
|
|
var fileList = scope.uploadQueues[studyIndex].fileList
|
|
var instanceUid = data.string('x00080018')
|
|
var instanceIndex = 0
|
|
while (
|
|
instanceIndex < fileList.length &&
|
|
fileList[instanceIndex].instanceUid !== instanceUid &&
|
|
(pixelDataElement || modality === 'SR')
|
|
) {
|
|
++instanceIndex
|
|
}
|
|
if (instanceIndex >= fileList.length) {
|
|
fileList.push({
|
|
instanceUid: instanceUid,
|
|
file: file,
|
|
})
|
|
}
|
|
scope.uploadQueues[studyIndex].dicomInfo.fileCount = fileList.length
|
|
scope.uploadQueues[studyIndex].dicomInfo.fileSize = fileList.reduce(
|
|
(prev, next) => {
|
|
return prev + next.file.size
|
|
},
|
|
0
|
|
)
|
|
|
|
var seriesUid = data.string('x0020000e')
|
|
var seriesList = scope.uploadQueues[studyIndex].seriesList
|
|
var seriesItem = seriesList.find(function (item) {
|
|
return item.seriesUid === seriesUid
|
|
})
|
|
if (!seriesItem && (pixelDataElement || modality === 'SR')) {
|
|
var date = data.string('x00080021')
|
|
var time = data.string('x00080031')
|
|
var seriesTime = ''
|
|
if (date) {
|
|
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) {
|
|
seriesTime = time ? `${date} ${time}` : `${date} 00:00:00`
|
|
}
|
|
const seriesDescriptionElement = data.elements.x0008103e
|
|
const seriesDescriptionBytes = new Uint8Array(
|
|
data.byteArray.buffer,
|
|
seriesDescriptionElement
|
|
? seriesDescriptionElement.dataOffset
|
|
: 0,
|
|
seriesDescriptionElement ? seriesDescriptionElement.length : 0
|
|
)
|
|
const seriesDescriptionStr = convertBytes(
|
|
data.string('x00080005'),
|
|
seriesDescriptionBytes
|
|
)
|
|
seriesItem = {
|
|
seriesUid: seriesUid,
|
|
seriesNumber: data.intString('x00200011') || 1,
|
|
modality: data.string('x00080060') || '',
|
|
description: seriesDescriptionStr,
|
|
seriesTime: seriesTime,
|
|
sliceThickness: data.string('x00180050') || '',
|
|
imagePositionPatient: data.string('x00200032') || '',
|
|
imageOrientationPatient: data.string('x00200037') || '',
|
|
sequenceName: data.string('x00180024') || '',
|
|
protocolName: data.string('x00181030') || '',
|
|
imagerPixelSpacing: data.string('x00181164') || '',
|
|
instanceList: [],
|
|
}
|
|
seriesList.push(seriesItem)
|
|
}
|
|
var instanceList = seriesItem.instanceList
|
|
var instanceItem = instanceList.find(function (item) {
|
|
return item.instanceUid === instanceUid
|
|
})
|
|
if (!instanceItem) {
|
|
var date = data.string('x00080023')
|
|
var time = data.string('x00080033')
|
|
var instanceTime = ''
|
|
if (date) {
|
|
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) {
|
|
instanceTime = time ? `${date} ${time}` : `${date} 00:00:00`
|
|
}
|
|
instanceItem = {
|
|
instanceUid: instanceUid,
|
|
instanceNumber: data.intString('x00200013') || 1,
|
|
frameCount: data.intString('x00280008') || 1,
|
|
instanceTime: instanceTime,
|
|
imageRows: data.uint16('x00280010') || 0,
|
|
imageColumns: data.uint16('x00280011') || 0,
|
|
sliceLocation: data.intString('x00201041') || 0,
|
|
sliceThickness: data.string('x00180050') || '',
|
|
numberOfFrames: data.intString('x00280008') || 0,
|
|
pixelSpacing: data.string('x00280030') || '',
|
|
imagerPixelSpacing: data.string('x00181164') || '',
|
|
frameOfReferenceUID: data.string('x00200052') || '',
|
|
windowCenter: data.string('x00281050') || '',
|
|
windowWidth: data.string('x00281051') || '',
|
|
modality: data.string('x00080060') || '',
|
|
file: file,
|
|
FileSize: file.size,
|
|
}
|
|
instanceList.push(instanceItem)
|
|
}
|
|
resolve()
|
|
} catch (error) {
|
|
console.log(error)
|
|
resolve()
|
|
}
|
|
}
|
|
reader.onerror = function (e) {
|
|
resolve()
|
|
}
|
|
reader.readAsArrayBuffer(file)
|
|
})
|
|
},
|
|
// 上传之前校验基本信息及检查是否已上传
|
|
beginUploadQueues() {
|
|
this.scanState = 'uploading'
|
|
this.studyErrorList = []
|
|
// console.log(this.uploadQueues, this.selectArr)
|
|
this.warningArr = []
|
|
for (let i = 0; i < this.selectArr.length; ++i) {
|
|
const index = this.selectArr[i].studyIndex
|
|
this.uploadQueues[index].uploadState.stateCode = 'uploading'
|
|
this.verifyBasicInfos(index)
|
|
}
|
|
if (this.warningArr.length) {
|
|
this.warning_cfg.visible = true
|
|
this.btnLoading = false
|
|
} else {
|
|
this.verifyStudy()
|
|
}
|
|
},
|
|
// 校验影像中检查时间、性别是否与受试者匹配
|
|
verifyBasicInfos(index) {
|
|
var warnings = []
|
|
if (
|
|
this.uploadQueues[index].dicomInfo.patientSex &&
|
|
this.form.SubjectSex
|
|
) {
|
|
if (
|
|
this.uploadQueues[index].dicomInfo.patientSex.substr(0, 1) !==
|
|
this.form.SubjectSex.substr(0, 1)
|
|
) {
|
|
warnings.push(
|
|
this.$t('trials:uploadDicomList:message:genderConsistent')
|
|
)
|
|
}
|
|
}
|
|
if (warnings.length > 0) {
|
|
this.warningArr.push({
|
|
index: this.uploadQueues[index].studyIndex + 1,
|
|
accNumber: this.uploadQueues[index].dicomInfo.accNumber,
|
|
warnings: warnings,
|
|
})
|
|
}
|
|
},
|
|
// 校验该检查是否上传过
|
|
async verifyStudy() {
|
|
this.btnLoading = true
|
|
var studyList = []
|
|
this.selectArr.forEach((item) => {
|
|
if (!item.uploadState.selected) {
|
|
studyList.push({
|
|
studyInstanceUid: item.dicomInfo.studyUid,
|
|
studyDate: item.dicomInfo.studyTime,
|
|
})
|
|
}
|
|
})
|
|
this.uploadCount = this.selectArr.length
|
|
this.uploadedCount = 0
|
|
for (let i = 0; i < this.selectArr.length; i++) {
|
|
const index = this.selectArr[i].studyIndex
|
|
if (!this.uploadQueues[index].uploadState.selected) {
|
|
await this.archiveStudy(index)
|
|
}
|
|
}
|
|
this.$set(this, 'uploadQueues', [
|
|
...this.uploadQueues.filter((v) => {
|
|
return (
|
|
!v.uploadState.record ||
|
|
(v.uploadState.record && !!v.uploadState.record.Failed.length)
|
|
)
|
|
}),
|
|
])
|
|
this.$nextTick(() => {
|
|
this.selectArr = []
|
|
this.uploadQueues.forEach((v, i) => {
|
|
if (v.uploadState.record) {
|
|
v.uploadState.selected = false
|
|
this.$refs.dicomFilesTable.toggleRowSelection(v, true)
|
|
}
|
|
v.studyIndex = i
|
|
})
|
|
this.$refs.pathClear.value = ''
|
|
this.list.forEach((item) => {
|
|
this.$refs[`pathClear_${item.Id}`].value = ''
|
|
})
|
|
this.btnLoading = false
|
|
if (this.studyErrorList.length > 0) {
|
|
let msg = this.$t('trials:uploadDicomFiles2:message:studyErrorList')
|
|
msg = msg.replaceAll('xxx', this.studyErrorList.join('、'))
|
|
this.$confirm(msg, this.$t('trials:hotkeys:message:tip'), {
|
|
confirmButtonText: this.$t(
|
|
'trials:uploadDicomFiles2:button:reupload'
|
|
),
|
|
}).then(() => {
|
|
this.beginUploadQueues()
|
|
})
|
|
}
|
|
})
|
|
},
|
|
// 上传影像并归档
|
|
archiveStudy(index, config) {
|
|
var scope = this
|
|
return new Promise(function (resolve, reject) {
|
|
try {
|
|
preArchiveDicomStudy({
|
|
trialId: scope.trialId,
|
|
subjectId: scope.SubjectId,
|
|
subjectVisitId: scope.subjectVisitId,
|
|
fileSize: scope.uploadQueues[index].dicomInfo.fileSize,
|
|
fileCount: scope.uploadQueues[index].dicomInfo.fileCount,
|
|
IsDicomReUpload:
|
|
scope.uploadQueues[index].uploadState.AllowReUpload,
|
|
})
|
|
.then(async (res) => {
|
|
scope.uploadQueues[index].dicomInfo.failedFileCount = 0
|
|
scope.$set(scope.uploadQueues[index].dicomInfo, 'isInit', true)
|
|
let dicomInfo = scope.uploadQueues[index].dicomInfo
|
|
let seriesNum = scope.uploadQueues[index].seriesList.length
|
|
let fileNum = scope.uploadQueues[index].fileList.length
|
|
let seriesList = scope.uploadQueues[index].seriesList
|
|
dicomInfo.seriesNum = seriesNum
|
|
dicomInfo.fileNum = fileNum
|
|
dicomInfo.subjectId = scope.SubjectId
|
|
dicomInfo.subjectVisitId = scope.subjectVisitId
|
|
let t = setInterval(() => {
|
|
dicomUploadInProgress({
|
|
trialId: scope.trialId,
|
|
studyInstanceUid: dicomInfo.studyUid,
|
|
}).then((res) => {})
|
|
}, 5000)
|
|
scope.myInterval.push(t)
|
|
let Record = {
|
|
Failed: [],
|
|
Existed: [],
|
|
Uploaded: [],
|
|
FileCount: 0,
|
|
}
|
|
let params = {
|
|
trialId: scope.trialId,
|
|
subjectId: scope.SubjectId,
|
|
subjectVisitId: scope.subjectVisitId,
|
|
studyMonitorId: res.Result,
|
|
failedFileCount: 0,
|
|
RecordPath: null,
|
|
study: {
|
|
studyId: dicomInfo.studyId,
|
|
studyInstanceUid: dicomInfo.studyUid,
|
|
studyTime: dicomInfo.studyTime,
|
|
description: dicomInfo.description,
|
|
seriesCount: dicomInfo.seriesNum,
|
|
instanceCount: dicomInfo.fileNum,
|
|
institutionName: dicomInfo.institutionName,
|
|
patientId: dicomInfo.patientId,
|
|
patientName: '',
|
|
patientAge: '',
|
|
patientSex: dicomInfo.patientSex,
|
|
accessionNumber: dicomInfo.accNumber,
|
|
patientBirthDate: '',
|
|
acquisitionTime: dicomInfo.acquisitionTime,
|
|
acquisitionNumber: dicomInfo.acquisitionNumber,
|
|
triggerTime: dicomInfo.triggerTime,
|
|
bodyPartExamined: '',
|
|
seriesList: [],
|
|
},
|
|
}
|
|
let arr = []
|
|
for (let i = 0; i < seriesList.length; i++) {
|
|
let v = seriesList[i]
|
|
let instanceList = []
|
|
let ImageResizePath
|
|
for (let ii = 0; ii < v.instanceList.length; ii++) {
|
|
arr.push(
|
|
(function () {
|
|
return new Promise(async (resolve1) => {
|
|
try {
|
|
let o = v.instanceList[ii]
|
|
let name = `${v.instanceList[ii].file.webkitRelativePath}_${v.instanceList[ii].instanceUid}`
|
|
if (o.isReUpload) {
|
|
dicomInfo.failedFileCount++
|
|
dicomInfo.uploadFileSize += o.file.size
|
|
Record.Existed.push(name)
|
|
Record.FileCount++
|
|
} else if (o.myPath) {
|
|
instanceList.push({
|
|
studyInstanceUid: dicomInfo.studyUid,
|
|
seriesInstanceUid: v.seriesUid,
|
|
sopInstanceUid: o.instanceUid,
|
|
instanceNumber: o.instanceNumber,
|
|
instanceTime: o.instanceTime,
|
|
imageRows: o.imageRows,
|
|
imageColumns: o.imageColumns,
|
|
sliceLocation: o.sliceLocation,
|
|
sliceThickness: o.sliceThickness,
|
|
numberOfFrames: o.numberOfFrames,
|
|
pixelSpacing: o.pixelSpacing,
|
|
imagerPixelSpacing: o.imagerPixelSpacing,
|
|
frameOfReferenceUID: o.frameOfReferenceUID,
|
|
windowCenter: o.windowCenter,
|
|
windowWidth: o.windowWidth,
|
|
path: o.myPath,
|
|
FileSize: o.FileSize,
|
|
})
|
|
Record.Uploaded.push(name)
|
|
dicomInfo.failedFileCount++
|
|
Record.FileCount++
|
|
} else {
|
|
let path = `/${params.trialId}/Image/${
|
|
params.subjectId
|
|
}/${params.subjectVisitId}/${
|
|
dicomInfo.visitTaskId
|
|
}/${scope.getGuid(
|
|
dicomInfo.studyUid +
|
|
v.seriesUid +
|
|
o.instanceUid +
|
|
params.trialId
|
|
)}`
|
|
if (scope.isClose) return
|
|
let res = await dcmUpload(
|
|
{
|
|
path: path,
|
|
file: o.file,
|
|
speed: true,
|
|
},
|
|
null,
|
|
(percentage, checkpoint, lastPer) => {
|
|
dicomInfo.uploadFileSize +=
|
|
checkpoint.size * (percentage - lastPer)
|
|
if (
|
|
dicomInfo.uploadFileSize > dicomInfo.fileSize
|
|
) {
|
|
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
|
}
|
|
}
|
|
)
|
|
if (!res || !res.url) {
|
|
params.failedFileCount++
|
|
} else {
|
|
if (ii === 0 && o.modality !== 'SR') {
|
|
try {
|
|
let fileId =
|
|
cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
|
o.file
|
|
)
|
|
let blob = await scope.dicomToPng(
|
|
fileId,
|
|
o.imageColumns,
|
|
o.imageRows
|
|
)
|
|
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.png`
|
|
let OSSclient = scope.OSSclient
|
|
let seriesRes = await OSSclient.put(
|
|
thumbnailPath,
|
|
blob
|
|
)
|
|
if (seriesRes && seriesRes.url) {
|
|
ImageResizePath = scope.$getObjectName(
|
|
seriesRes.url
|
|
)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
}
|
|
if (res && res.url) {
|
|
instanceList.push({
|
|
studyInstanceUid: dicomInfo.studyUid,
|
|
seriesInstanceUid: v.seriesUid,
|
|
sopInstanceUid: o.instanceUid,
|
|
instanceNumber: o.instanceNumber,
|
|
instanceTime: o.instanceTime,
|
|
imageRows: o.imageRows,
|
|
imageColumns: o.imageColumns,
|
|
sliceLocation: o.sliceLocation,
|
|
sliceThickness: o.sliceThickness,
|
|
numberOfFrames: o.numberOfFrames,
|
|
pixelSpacing: o.pixelSpacing,
|
|
imagerPixelSpacing: o.imagerPixelSpacing,
|
|
frameOfReferenceUID: o.frameOfReferenceUID,
|
|
windowCenter: o.windowCenter,
|
|
windowWidth: o.windowWidth,
|
|
path: scope.$getObjectName(res.url),
|
|
FileSize: o.FileSize,
|
|
})
|
|
o.myPath = scope.$getObjectName(res.url)
|
|
Record.Uploaded.push(name)
|
|
dicomInfo.failedFileCount++
|
|
Record.FileCount++
|
|
} else {
|
|
Record.Failed.push(name)
|
|
Record.FileCount++
|
|
}
|
|
}
|
|
resolve1()
|
|
} catch (e) {
|
|
console.log(e)
|
|
resolve1()
|
|
}
|
|
})
|
|
})()
|
|
)
|
|
if (
|
|
(arr.length >= 10 || ii === v.instanceList.length - 1) &&
|
|
!scope.isClose
|
|
) {
|
|
await Promise.all(arr)
|
|
arr = []
|
|
}
|
|
}
|
|
params.study.seriesList.push({
|
|
studyInstanceUid: dicomInfo.studyUid,
|
|
seriesInstanceUid: v.seriesUid,
|
|
seriesNumber: v.seriesNumber,
|
|
seriesTime: v.seriesTime,
|
|
sliceThickness: v.sliceThickness,
|
|
imagePositionPatient: v.imagePositionPatient,
|
|
imageOrientationPatient: v.imageOrientationPatient,
|
|
sequenceName: v.sequenceName,
|
|
protocolName: v.protocolName,
|
|
imagerPixelSpacing: v.imagerPixelSpacing,
|
|
acquisitionTime: dicomInfo.acquisitionTime,
|
|
acquisitionNumber: dicomInfo.acquisitionNumber,
|
|
triggerTime: dicomInfo.triggerTime,
|
|
modality: v.modality,
|
|
description: v.description,
|
|
instanceCount: v.instanceList.length,
|
|
bodyPartExamined: dicomInfo.bodyPart,
|
|
instanceList: instanceList,
|
|
ImageResizePath: ImageResizePath,
|
|
})
|
|
}
|
|
let text = JSON.stringify(Record)
|
|
let logJsonBlob = scope.generateTxtFile(text)
|
|
let logJsonObjectName = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${params.studyMonitorId}.txt`
|
|
let logRes
|
|
try {
|
|
logRes = await scope.OSSclient.put(
|
|
logJsonObjectName,
|
|
logJsonBlob
|
|
)
|
|
} catch (e) {
|
|
scope.uploadQueues[index].uploadState.record = Record
|
|
scope.studyErrorList.push(dicomInfo.accNumber)
|
|
clearInterval(t)
|
|
resolve()
|
|
}
|
|
for (let i = 0; i < seriesList.length; i++) {
|
|
let v = seriesList[i]
|
|
let o = params.study.seriesList.find((o) => {
|
|
return o.seriesInstanceUid === v.seriesUid
|
|
})
|
|
if (o && !o.ImageResizePath) {
|
|
let fileId =
|
|
cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
|
v.instanceList[0].file
|
|
)
|
|
let blob = await scope.dicomToPng(
|
|
fileId,
|
|
v.instanceList[0].imageColumns,
|
|
v.instanceList[0].imageRows
|
|
)
|
|
let thumbnailPath = `/${params.trialId}/Image/${params.trialSiteId}/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.studyUid}/${v.seriesUid}.png`
|
|
let OSSclient = scope.OSSclient
|
|
try {
|
|
let seriesRes = await OSSclient.put(thumbnailPath, blob)
|
|
if (seriesRes && seriesRes.url) {
|
|
o.ImageResizePath = scope.$getObjectName(seriesRes.url)
|
|
}
|
|
} catch (e) {
|
|
console.log(e)
|
|
}
|
|
}
|
|
}
|
|
if (logRes && logRes.url) {
|
|
params.study.instanceCount = dicomInfo.failedFileCount
|
|
params.RecordPath = scope.$getObjectName(logRes.url)
|
|
if (scope.isClose) return false
|
|
console.log(params)
|
|
params.VisitTaskId = dicomInfo.visitTaskId
|
|
addOrUpdateArchiveTaskStudy(params)
|
|
.then((res) => {
|
|
if (dicomInfo.failedFileCount === dicomInfo.fileCount) {
|
|
scope.$message.success(
|
|
scope.$t('trials:uploadDicomList:label:uploaded')
|
|
)
|
|
} else {
|
|
scope.studyErrorList.push(dicomInfo.accNumber)
|
|
}
|
|
scope.uploadQueues[index].uploadState.record = Record
|
|
scope.getList()
|
|
if (
|
|
scope.$route.path !==
|
|
'/trials/trials-panel/visit/crc-question'
|
|
) {
|
|
scope.$emit('getList')
|
|
}
|
|
clearInterval(t)
|
|
resolve()
|
|
})
|
|
.catch((res) => {
|
|
scope.uploadQueues[index].uploadState.record = Record
|
|
scope.studyErrorList.push(dicomInfo.accNumber)
|
|
clearInterval(t)
|
|
resolve()
|
|
})
|
|
} else {
|
|
scope.uploadQueues[index].uploadState.record = Record
|
|
scope.studyErrorList.push(dicomInfo.accNumber)
|
|
clearInterval(t)
|
|
resolve()
|
|
}
|
|
})
|
|
.catch((err) => {
|
|
console.log(err)
|
|
let Record = {
|
|
Failed: [],
|
|
Existed: [],
|
|
Uploaded: [],
|
|
FileCount: 0,
|
|
}
|
|
let fileList = scope.uploadQueues[index].fileList
|
|
fileList.forEach((v) => {
|
|
Record.Failed.push(v.webkitRelativePath)
|
|
})
|
|
scope.uploadQueues[index].uploadState.record = Record
|
|
scope.studyErrorList.push(dicomInfo.accNumber)
|
|
resolve()
|
|
})
|
|
} catch (e) {
|
|
console.log(e)
|
|
resolve()
|
|
}
|
|
})
|
|
},
|
|
dicomToPng(imageId, width, height) {
|
|
return new Promise((resolve) => {
|
|
cornerstone.loadImage(imageId).then(async (image) => {
|
|
let canvas = document.createElement('canvas')
|
|
canvas.width = width
|
|
canvas.height = height
|
|
if (image) {
|
|
cornerstone.renderToCanvas(canvas, image)
|
|
// 将 Canvas 图像对象转换为 PNG 格式
|
|
let blob = await this.canvasToBlob(canvas)
|
|
resolve(blob)
|
|
} else {
|
|
resolve()
|
|
}
|
|
})
|
|
}).catch((reason) => {
|
|
reason()
|
|
})
|
|
},
|
|
canvasToBlob(canvas) {
|
|
return new Promise((resolve) => {
|
|
canvas.toBlob((blob) => {
|
|
resolve(blob)
|
|
})
|
|
})
|
|
},
|
|
generateTxtFile(text) {
|
|
let blob = new Blob(['\ufeff', text], { type: 'text/plain' })
|
|
return blob
|
|
},
|
|
// 预览阅片影像
|
|
handleViewReadingImages(row) {
|
|
if (this.open) {
|
|
this.open.close()
|
|
}
|
|
var token = getToken()
|
|
let trialId = this.$route.query.trialId
|
|
const routeData = this.$router.resolve({
|
|
path: `/showvisitdicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
|
|
})
|
|
this.open = window.open(routeData.href, '_blank')
|
|
},
|
|
},
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.top {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
}
|
|
.btnBox,
|
|
.form-group {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
#inputForm .file-input {
|
|
position: relative;
|
|
overflow: hidden;
|
|
display: inline-block;
|
|
}
|
|
#inputForm .file-input input[type='file'] {
|
|
position: absolute;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
opacity: 0;
|
|
cursor: pointer;
|
|
}
|
|
</style> |