irc_web/.svn/pristine/b6/b6ed0ab890233b73b0ce66bf777...

1082 lines
38 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="upload-dicom-files-wrapper">
<!-- 已上传的dicom影像记录 -->
<div class="functions" style="text-align:right">
<!-- //批量删除已上传的影像 -->
<el-button
:disabled="deleteArr.length === 0"
type="primary"
size="small"
icon="el-icon-delete"
@click="handleBatchDelete"
>
{{ $t('trials:uploadedDicoms:action:delete') }}
</el-button>
<!-- 预览 -->
<el-button
type="primary"
icon="el-icon-view"
size="small"
:disabled="studyList.length === 0"
@click="handlePreviewAllFiles"
>
{{ $t('trials:uploadedDicoms:action:preview') }}
</el-button>
</div>
<el-table
v-loading="studyLoading"
:data="studyList"
style="width: 100%"
:row-class-name="tableRowClassName"
max-height="250"
@selection-change="handleUploadedSelectionChange"
>
<el-table-column
type="selection"
width="55"
/>
<!-- 检查编号 -->
<el-table-column
prop="StudyCode"
:label="$t('trials:uploadedDicoms:table:studyId')"
min-width="80"
show-overflow-tooltip
/>
<!-- 检查类型 -->
<el-table-column
prop="Modalities"
:label="$t('trials:uploadedDicoms:table:modality')"
min-width="80"
show-overflow-tooltip
/>
<!-- 检查部位 -->
<el-table-column
prop="BodyPartExamined"
:label="$t('trials:uploadedDicoms:table:bodyPart')"
min-width="100"
show-overflow-tooltip
/>
<!-- 序列数量 -->
<el-table-column
prop="SeriesCount"
:label="$t('trials:uploadedDicoms:table:seriesCount')"
min-width="100"
show-overflow-tooltip
/>
<!-- 图像数量 -->
<el-table-column
prop="InstanceCount"
:label="$t('trials:uploadedDicoms:table:instanceCount')"
min-width="100"
show-overflow-tooltip
/>
<!-- 检查日期 -->
<el-table-column
prop="StudyTime"
:label="$t('trials:uploadedDicoms:table:studyDate')"
min-width="120"
show-overflow-tooltip
>
<template slot-scope="scope">
{{ scope.row.StudyTime ? moment(scope.row.StudyTime).format('YYYY-MM-DD'):'' }}
</template>
</el-table-column>
<!-- 上传时间 -->
<el-table-column
prop="UploadedTime"
:label="$t('trials:uploadedDicoms:table:uploadedTime')"
min-width="80"
show-overflow-tooltip
/>
<el-table-column :label="$t('common:action:action')" min-width="100" fixed="right">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
:disabled="scope.row.SeriesCount === 0 || scope.row.IsDeleted"
:title="$t('trials:uploadedDicoms:action:preview')"
circle
@click="handleViewStudy(scope.row)"
/>
<!-- 删除 -->
<el-button
icon="el-icon-delete"
:disabled="scope.row.IsDeleted"
:title="$t('trials:uploadedDicoms:action:delete')"
circle
@click="handleDeleteStudy(scope.row)"
/>
</template>
</el-table-column>
</el-table>
<!-- 多文件上传 -->
<form id="inputForm" ref="uploadForm">
<el-divider content-position="left">{{ $t('trials:uploadedDicoms:title:dicomFilesOnly') }}</el-divider>
<div class="form-group">
<div id="directoryInputWrapper" class="btn btn-link file-input">
<el-button size="small">{{ $t('trials:uploadedDicomsicom:button:selectFolder') }}</el-button>
<input
type="file"
name="file"
webkitdirectory
multiple
@change="beginScanFiles($event)"
>
</div>
</div>
</form>
<!-- 文件列表 -->
<el-table
ref="dicomFilesTable"
:data="uploadQueues"
class="dicomFiles-table"
@selection-change="handleSelectionChange"
>
<el-table-column
type="selection"
width="55"
:selectable="handleSelectable"
/>
<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:status')" min-width="120" show-overflow-tooltip>
<template slot-scope="scope">
<el-progress v-show="scope.row.uploadState.progressValue && scope.row.uploadState.progressValue!= 100" :percentage="scope.row.uploadState.progressValue" />
<el-progress v-show="scope.row.uploadState.UpdataValue && scope.row.uploadState.UpdataValue!= 100" color="#409eff" :format="format(scope.row.uploadState.UpdataValue)" :percentage="scope.row.uploadState.UpdataValue" />
<el-tooltip v-if="scope.row.uploadState.stateCode === 'Uploading not allowed'" class="item" effect="dark" :content="scope.row.uploadState.errorMessage" placement="bottom">
<span>{{ scope.row.uploadState.stateText }}</span>
</el-tooltip>
<span v-else>{{ scope.row.uploadState.stateText }}</span>
</template>
</el-table-column>
<el-table-column
:label="$t('trials:uploadDicomList:table:stats')"
min-width="140"
show-overflow-tooltip
>
<template slot-scope="scope">
<div style="display: flex;justify-content: flex-start;align-items: center">
<div
v-if="scope.row.uploadState.totalCount"
style="text-align: center"
>
{{
scope.row.uploadState.totalCount +
' / ' +
scope.row.uploadState.successCount +
' / ' +
scope.row.uploadState.failedCount
}}
</div>
<div v-if="scope.row.uploadState.failedCount > 0">
<el-button
type="primary"
size="small"
@click="exportFailedFiles(scope.row.uploadState.ErrorFiles)"
>
{{ $t('trials:uploadDicomList:button:exportFailed') }}
</el-button>
</div>
</div>
</template>
</el-table-column>
<el-table-column v-show="isScan" :label="$t('common:action:action')" width="200">
<template slot-scope="scope">
<!-- 预览 -->
<el-button
icon="el-icon-view"
circle
:title="$t('trials:uploadedDicoms:action:preview')"
size="small"
@click="handlePreview(scope.row.dicomInfo.studyUid)"
/>
<!-- 移除 -->
<el-button
icon="el-icon-delete"
circle
:title="$t('trials:uploadedDicoms:action:delete')"
size="small"
:disabled="scope.row.uploadState.stateCode !== ''"
@click="handleDelete(scope.$index, scope.row)"
/>
</template>
</el-table-column>
</el-table>
<div style="text-align:right;padding: 10px 0px">
<!-- 关闭 -->
<!-- <el-button :disabled="btnLoading" size="small" type="primary" @click="cancel">
{{ $t('trials:uploadDicomList:button:close') }}
</el-button> -->
<!-- 上传 -->
<el-button
size="small"
type="primary"
:disabled="selectArr.length == 0 || !isScan"
:loading="btnLoading || uploadCount !== uploadedCount"
@click="beginUploadQueues"
>
{{ $t('trials:uploadDicomList:button:upload') }}
</el-button>
</div>
<!-- 预览影像模态框 -->
<el-dialog
v-if="previewVisible"
:fullscreen="true"
:show-close="true"
:visible.sync="previewVisible"
append-to-body
>
<DicomPreview :uid="uid" />
</el-dialog>
<!-- 校验警告信息模态框 -->
<el-dialog
v-if="warning_cfg.visible"
:visible.sync="warning_cfg.visible"
width="500px"
:close-on-click-modal="false"
append-to-body
title="Warning"
custom-class="warning-dialog"
>
<div style="border:1px solid #e0e0e0;padding:10px;">
<!-- Information from DICOM headers not consistent with that of this subject -->
<div style="color: red;font-size:14px;margin-bottom:10px;">
{{ $t('trials:uploadDicomList:message:informationConsistent') }}:
</div>
<div v-for="(item,i) in warningArr" :key="item.index">
<div>{{ `(${i+1}). ACC: ${item.accNumber}` }}</div>
<div v-for="(warning,index) in item.warnings" :key="index" style="margin:10px 0px;font-size:13px;">
<ul>
<li>{{ warning }}</li>
</ul>
</div>
</div>
</div>
<div slot="footer" class="base-modal-footer">
<el-button size="small" type="primary" @click="handleCancelWarnVisible">
{{ $t('common:button:cancel') }}
</el-button>
<el-button size="small" type="primary" @click="handleContinueUpload">
{{ $t('trials:uploadDicomList:button:upload') }}
</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import {
batchVerifyStudyAllowUpload, getSubjectVisitUploadedStudyList, deleteStudyList
} from '@/api/trials'
import store from '@/store'
import * as dicomParser from 'dicom-parser'
import * as signalR from '@microsoft/signalr'
import DicomPreview from '@/views/dicom-show/dicom-preview'
import dicomStore from '@/utils/dicom-store'
import { getToken } from '@/utils/auth'
import moment from 'moment'
export default {
name: 'UploadDicomFiles',
components: { DicomPreview },
props: {
data: {
type: Object,
default() {
return {}
}
},
subjectVisitId: {
type: String,
required: true
},
subjectId: {
type: String,
required: true
}
},
data() {
return {
uploadQueues: dicomStore.studyList, // 上传队列
selectArr: [], // 已勾选待上传文件
scanState: '', // 当前上传队列上传状态
form: {
SiteName: '',
SubjectName: '',
VisitName: '',
SubjectId: '',
VisitNum: null
},
btnLoading: false,
previewVisible: false,
warning_cfg: { visible: false },
warningArr: [],
isScan: false,
studyLoading: false,
studyList: [],
deleteArr: [],
trialId: '',
moment,
uploadCount: 0,
uploadedCount: 0,
wsList: []
}
},
mounted() {
this.trialId = this.$route.query.trialId
if (Object.keys(this.data).length) {
this.form = { ...this.data }
}
let connection = new signalR.HubConnectionBuilder()
.withUrl("/UploadHub", { accessTokenFactory: () => getToken() })
.configureLogging(signalR.LogLevel.Information)
.withAutomaticReconnect()
.build()
connection.start()
connection.on("ReceivProgressAsync", (id, num) => {
this.onUploadProgress2(id, num)
});
this.getStudyInfo()
},
methods: {
format(v) {
return v
},
// 获取已上传的dicom影像
getStudyInfo() {
this.studyLoading = true
getSubjectVisitUploadedStudyList(this.subjectVisitId).then(res => {
this.studyList = res.Result
this.studyLoading = false
}).catch(() => { this.studyLoading = false })
},
// 预览单个检查影像
handleViewStudy(row) {
var token = getToken()
const routeData = this.$router.resolve({
path: `/showdicom?studyId=${row.StudyId}&TokenKey=${token}&type=Study`
})
window.open(routeData.href, '_blank')
},
// 预览所有影像
handlePreviewAllFiles() {
var token = getToken()
const routeData = this.$router.resolve({
path: `/showvisitdicoms?trialId=${this.data.TrialId}&visitInfo=${this.data.VisitName}(${this.data.VisitNum})&subjectVisitId=${this.data.Id}&TokenKey=${token}`
})
window.open(routeData.href, '_blank')
},
// 扫描待上传文件
beginScanFiles(e) {
var files = e.target.files
if (files.length > 0) {
console.log(files)
var checkFiles = [...files]
var isHasDicom = checkFiles.find(v => {
return v.name.split('.')[v.name.split('.').length - 1] === 'DCM' || v.name.split('.')[v.name.split('.').length - 1] === 'dcm'
})
if (!isHasDicom) {
this.$message.error(this.$t('trials:trials-panel:message:notIsHasDicom'))
return
}
var scope = this
scope.scanState = ''
scope.isScan = false
var p = new Promise(function(resolve) {
resolve()
})
for (var i = 0; i < files.length; ++i) {
(function(index) {
p = p.then(function() {
return scope.parseDicomFile(files[index])
})
})(i)
}
p.then(function(result) {
scope.scanState = 'finished'
scope.isScan = true
})
}
},
// 按序列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 studyUid = data.string('x0020000d')
var studyIndex = 0
while (
studyIndex < scope.uploadQueues.length &&
scope.uploadQueues[studyIndex].dicomInfo.studyUid !== studyUid
) {
++studyIndex
}
if (studyIndex >= scope.uploadQueues.length) {
var date = data.string('x00080020')
var time = data.string('x00080030')
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.substr(0, 2)}:${time.substr(2, 2)}:${time.substr(4, 2)}`
time = `${time.substring(0, 2)}:${time.substring(2, 4)}:${time.substring(4, 6)}`
}
var studyTime = time ? `${date} ${time}` : `${date} 00:00:00`
scope.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 = 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
) {
++instanceIndex
}
if (instanceIndex >= fileList.length) {
fileList.push({
instanceUid: instanceUid,
file: file
})
}
var seriesUid = data.string('x0020000e')
var seriesList = scope.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,
instanceNumber: data.intString('x00200013') || 1,
frameCount: data.intString('x00280008') || 1,
file: file
}
instanceList.push(instanceItem)
}
resolve()
} catch (error) {
console.log(error)
resolve()
}
}
reader.onerror = function(e) {
resolve()
}
reader.readAsArrayBuffer(file)
})
},
// 上传之前校验基本信息及检查是否已上传
beginUploadQueues() {
this.scanState = 'uploading'
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
} else {
this.verifyStudy()
}
},
// 校验影像中检查时间、性别是否与受试者匹配
verifyBasicInfos(index) {
// const studyTime = moment(this.uploadQueues[index].dicomInfo.studyTime).format('YYYY-MM-DD')
var warnings = []
// if (studyTime && studyTime < this.form.SVSTDTC) {
// warnings.push('Study Date earlier than Visit Start Date.')
// }
// if (studyTime && studyTime > this.form.SVSTDTC) {
// if (this.compare(studyTime, this.form.SVSTDTC) > 7) { warnings.push('Study Date later than Visit Start Date for more than one week.') }
// }
// const patientAge = this.uploadQueues[index].dicomInfo.patientAge
// if (patientAge && this.form.SubjectAge) {
// var age = patientAge.match(/\d+(.\d+)?/g)
// if (Math.abs(parseInt(age[0]) - parseInt(this.form.SubjectAge)) >= 1) {
// warnings.push('Patient Age not consistent with Subject Age.')
// }
// }
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 })
}
},
// 校验该检查是否上传过
verifyStudy() {
this.btnLoading = true
var studyList = []
this.selectArr.forEach(item => {
studyList.push({ studyInstanceUid: item.dicomInfo.studyUid, studyDate: item.dicomInfo.studyTime })
})
var param = {
trialId: this.trialId,
subjectId: this.subjectId,
subjectVisitId: this.subjectVisitId,
visitNum: this.form.VisitNum,
studyInstanceUidList: studyList
}
batchVerifyStudyAllowUpload(param).then((res) => {
var messageArr = []
res.Result.forEach((item) => {
// 不能上传或不能重传时,收集校验结果提示,并取消勾选,设置上传状态
if (item.ErrorMesseage) {
const i = this.uploadQueues.findIndex((value) => value.dicomInfo.studyUid === item.StudyInstanceUid)
// Uploading not allowed
this.uploadQueues[i].uploadState.stateText = this.$t('trials:uploadDicomList:label:uploadingNotAllowed')
this.uploadQueues[i].uploadState.selected = true
this.uploadQueues[i].uploadState.stateCode = 'Uploading not allowed'
this.uploadQueues[i].uploadState.errorMessage = item.ErrorMesseage
this.$refs.dicomFilesTable.toggleRowSelection(this.uploadQueues[i])
// const msg = `ACC:${this.uploadQueues[i].dicomInfo.accNumber}, ${item.ErrorMesseage}`
const msg = `${item.ErrorMesseage}`
messageArr.push(msg)
}
// 可以重传时记录需要被覆盖的检查ID
if (item.AllowReUpload) {
const i = this.uploadQueues.findIndex((value) => value.dicomInfo.studyUid === item.StudyInstanceUid)
this.uploadQueues[i].AbandonStudyId = item.StudyInfo ? item.StudyInfo.Id : ''
}
})
if (messageArr.length > 0) {
var li = messageArr.map(msg => { return `<li>${msg}</li>` })
const content = `
<div>
<ol>
${li.join('')}
</ol>
</div>`
this.$alert(content, this.$t('trials:uploadDicomList:label:prompt'),
{
confirmButtonText: this.$t('trials:uploadDicomList:label:confirm'),
dangerouslyUseHTMLString: true,
callback: (action) => {}
})
this.btnLoading = false
}
var results = []
this.uploadCount = this.selectArr.length
this.uploadedCount = 0
for (let i = 0; i < this.selectArr.length; ++i) {
const index = this.selectArr[i].studyIndex
results.push(this.archiveStudy(index))
}
Promise.all(results).then(_ => {
this.btnLoading = false
}).catch(_ => {
this.btnLoading = false
})
}).catch(_ => { this.btnLoading = false })
},
objectToQuery() {
let obj = arguments[0]
let prefix = arguments[1]
if (typeof obj !== 'object') return ''
const attrs = Object.keys(obj)
return attrs.reduce((query, attr, index) => {
// 判断是否是第一层第一个循环
if (index === 0 && !prefix) query += '?'
if (typeof obj[attr] === 'object') {
const subPrefix = prefix ? `${prefix}[${attr}]` : attr
query += this.objectToQuery(obj[attr], subPrefix)
} else {
if (prefix) {
query += `${prefix}[${attr}]=${obj[attr]}`
} else {
query += `${attr}=${obj[attr]}`
}
}
// 判断是否是第一层最后一个循环
if (index !== attrs.length - 1) query += '&'
return query
}, '')
},
// 上传影像并归档
archiveStudy(index) {
var scope = this
return new Promise(function(resolve, reject) {
var data = new FormData()
var dicomInfo = scope.uploadQueues[index].dicomInfo
var seriesNum = scope.uploadQueues[index].seriesList.length
var fileNum = scope.uploadQueues[index].fileList.length
dicomInfo.seriesNum = seriesNum
dicomInfo.fileNum = fileNum
dicomInfo.siteId = scope.data.SiteId
dicomInfo.subjectId = scope.data.SubjectId
dicomInfo.subjectVisitId = scope.subjectVisitId
var params = {
trialId: scope.trialId,
subjectVisitId: scope.subjectVisitId,
studyInstanceUid: scope.uploadQueues[index].dicomInfo.studyUid
}
// data.append('subjectVisitId', scope.subjectVisitId)
// data.append('studyInstanceUid', scope.uploadQueues[index].dicomInfo.studyUid)
if (scope.uploadQueues[index].AbandonStudyId) {
params.abandonStudyId = scope.uploadQueues[index].AbandonStudyId
// data.append('abandonStudyId', scope.uploadQueues[index].AbandonStudyId)
}
for (var i = 0; i < scope.uploadQueues[index].fileList.length; ++i) {
data.append('file', scope.uploadQueues[index].fileList[i].file)
}
scope.btnLoading = true
var xhr = new XMLHttpRequest()
xhr.open('POST', `/api/study/archiveStudy${scope.objectToQuery(params)}`)
xhr.setRequestHeader('Authorization', `Bearer ${store.getters.token}`)
// xhr.setRequestHeader('Content-Type', 'octet-stream')
xhr.timeout = 2 * 360000 // 超时时间,单位是毫秒
xhr.responseType = 'text'
xhr.onload = function(e) {
scope.onUploadCompleted(e, index)
resolve()
}
xhr.onerror = function(e) {
scope.onUploadError(e, index)
resolve()
}
xhr.upload.onprogress = function(e) {
scope.onUploadProgress(e, index)
}
// xhr.onprogress = function(e) {
// console.log('请求完成')
// scope.onUploadProgress(e, index)
// }
xhr.send(data)
var uploadState = scope.uploadQueues[index].uploadState
// 'Uploading...'
uploadState.stateText = `${this.$t('trials:uploadDicomList:label:uploading')}...`
uploadState.beginUploadTime = new Date()
uploadState.progressValue = 0
})
},
// 上传成功回调
onUploadCompleted: function(e, index) {
this.uploadedCount++
var uploadState = this.uploadQueues[index].uploadState
// this.btnLoading = false
if (e.target.status === 200) {
const responseObj = JSON.parse(e.target.responseText)
uploadState.stateCode = 'Finished'
if (responseObj.IsSuccess) {
this.uploadQueues[index].uploadState.selected = true
const i = this.selectArr.findIndex(item => { item.studyIndex === index })
this.selectArr.splice(i, 1)
this.$refs.dicomFilesTable.toggleRowSelection(this.uploadQueues[index])
uploadState.totalCount = responseObj.Result.ReceivedFileCount
uploadState.failedCount = responseObj.Result.ErrorFiles.length
uploadState.successCount = uploadState.totalCount - uploadState.failedCount
uploadState.ErrorFiles = responseObj.Result.ErrorFiles
if (responseObj.Result.ArchivedDicomStudies.length > 0) {
// Uploaded
uploadState.stateText = this.$t('trials:uploadDicomList:label:uploaded')
this.scanState = 'Uploaded'
this.getStudyInfo()
this.$emit('getList')
}
} else {
// Failed
this.uploadQueues[index].uploadState.stateText = this.$t('trials:uploadDicomList:label:uploadFailed')
this.scanState = 'Failed'
if (responseObj.ErrorMessage) {
this.$message.error(responseObj.ErrorMessage)
}
}
this.wariningMes = ''
} else {
uploadState.stateCode = 'Failed'
// Failed
uploadState.stateText = this.$t('trials:uploadDicomList:label:uploadFailed')
this.scanState = 'Failed'
}
this.$forceUpdate()
},
// 上传失败回调
onUploadError: function(e, index) {
this.uploadedCount++
// this.btnLoading = false
var uploadState = this.uploadQueues[index].uploadState
uploadState.stateCode = 'Failed'
uploadState.stateText = this.$t('trials:uploadDicomList:label:uploadFailed')
this.scanState = 'Failed'
},
onUploadProgress2(id, num) {
let info = this.uploadQueues.find(v => {
return v.dicomInfo.studyUid === id
})
if (info) {
// fileNum 总数
this.$set(info.uploadState, 'UpdataValue', Math.floor(num / info.dicomInfo.fileNum * 100))
this.$set(info.uploadState, 'stateText', `影像上传中`)
console.log(info.uploadState.UpdataValue)
}
},
// 上传进程
onUploadProgress: function(e, index) {
if (e.lengthComputable) {
var percent = Math.floor(e.loaded / e.total * 100)
console.log(e.loaded, e.total, percent)
// Uploading
// this.uploadQueues[index].uploadState.stateText = `${this.$t('trials:uploadDicomList:label:uploading')}...`
// this.uploadQueues[index].uploadState.progressValue = percent
this.$set(this.uploadQueues[index].uploadState, 'stateText', `影像处理中`)
this.$set(this.uploadQueues[index].uploadState, 'progressValue', percent)
// if (percent === 100) {
// this.uploadQueues[index].uploadState.progressValue = 100
// }
// this.$forceUpdate()
}
},
// warning弹框取消按钮回调
handleCancelWarnVisible() {
this.warning_cfg.visible = false
for (var i = 0; i < this.selectArr.length; ++i) {
const index = this.selectArr[i].studyIndex
this.uploadQueues[index].uploadState.stateCode = ''
}
},
// 忽略warning继续上传
handleContinueUpload() {
this.warning_cfg.visible = false
this.verifyStudy()
},
// 预览影像
handlePreview(uid) {
this.previewVisible = true
this.uid = uid
},
// 删除影像列表中的某个影像
handleDelete(index, row) {
this.$confirm(this.$t('trials:uploadedDicoms:message:deleteMes'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
this.$refs.uploadForm.reset()
this.selectArr = []
this.uploadQueues.splice(index, 1)
})
},
// 当选择项发生变化时收集待上传文件数据
handleSelectionChange(selection) {
selection.sort((n1, n2) => {
return n1.studyIndex - n2.studyIndex
})
this.selectArr = selection
},
// 根据是否上传状态决定CheckBox 是否可以勾选
handleSelectable(row) {
if (row.uploadState.selected) {
return false
} else {
return true
}
},
// 收集已上传文件列表勾选项
handleUploadedSelectionChange(selection) {
this.deleteArr = []
selection.forEach(item => {
this.deleteArr.push(item.StudyId)
})
},
// 批量删除已上传的影像
handleBatchDelete() {
this.$confirm(this.$t('trials:uploadedDicoms:message:deleteMes'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
this.studyLoading = true
deleteStudyList(this.trialId, this.subjectVisitId, this.deleteArr)
.then(res => {
if (res.IsSuccess) {
this.getStudyInfo()
this.$emit('getList')
this.$message.success(this.$t('trials:uploadedDicoms:message:deleteSuccessfully'))
}
}).catch(() => {
this.studyLoading = true
})
}).catch(() => {})
},
// 删除已上传的某个检查
handleDeleteStudy(row) {
this.$confirm(this.$t('trials:uploadedDicoms:message:deleteMes'), {
type: 'warning',
distinguishCancelAndClose: true
})
.then(() => {
this.studyLoading = true
deleteStudyList(this.trialId, this.subjectVisitId, [row.StudyId])
.then(res => {
if (res.IsSuccess) {
this.getStudyInfo()
this.$emit('getList')
this.$message.success(this.$t('trials:uploadedDicoms:message:deleteSuccessfully'))
}
}).catch(() => {
this.studyLoading = true
})
}).catch(() => {})
},
// cancel按钮回调
cancel() {
this.scanState = 'cancelling'
// 关闭上传模态框
this.$emit('close')
},
compare(start, end) {
start = new Date(start)
start = start.getTime()
end = new Date(end)
end = end.getTime()
var time = 0
if (start > end) {
time = start - end
} else {
time = end - start
}
return Math.floor(time / 86400000)
},
exportFailedFiles(errorFiles) {
var elementA = document.createElement('a')
var str = ''
errorFiles.forEach((el) => {
str += el + '\n'
})
elementA.setAttribute('href', 'data:text/html;charset=utf-8,' + str)
elementA.setAttribute('download', +new Date() + '.txt')
elementA.style.display = 'none'
document.body.appendChild(elementA)
elementA.click()
document.body.removeChild(elementA)
},
// 设置已删除序列行样式
tableRowClassName({ row, rowIndex }) {
if (row.IsDeleted) {
return 'delete-row'
} else {
return ''
}
}
}
}
</script>
<style lang="scss">
.upload-dicom-files-wrapper{
.dicomFiles-table{
.el-table__body-wrapper{
height: 300px;
overflow-y: auto;
}
}
.delete-row{
text-decoration-line: line-through;
color: #c0c4cc;
}
.previewActive:hover {
cursor: pointer;
color: #33dac1;
}
#inputForm label {
font-weight: normal;
}
#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;
}
#inputForm #listWrapper {
margin-top: 10px;
margin-bottom: 50px;
}
#inputForm #listWrapper a {
text-decoration: none;
}
#inputForm .text-left {
text-align: left;
}
.colorOfRed{
color:#f44336;
}
}
</style>