1925 lines
75 KiB
Vue
1925 lines
75 KiB
Vue
<template>
|
||
<div class="upload-dicom-files-wrapper">
|
||
<!-- 已上传的dicom影像记录 -->
|
||
<!-- <el-divider content-position="left">{{
|
||
$t('trials:uploadedDicoms:title:dicomUploaded')
|
||
}}</el-divider> -->
|
||
<div style="margin: 10px 0">
|
||
{{ $t('trials:uploadedDicoms:title:dicomUploaded') }}
|
||
</div>
|
||
<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"
|
||
:default-sort="{ prop: 'UploadedTime', order: 'ascending' }">
|
||
<el-table-column type="selection" width="55" />
|
||
<!-- 检查编号 -->
|
||
<el-table-column prop="StudyCode" :label="$t('trials:uploadedDicoms:table:studyId')" min-width="80"
|
||
show-overflow-tooltip sortable>
|
||
<template slot-scope="scope">
|
||
<el-tooltip placement="top" v-if="
|
||
(() => {
|
||
var r = false
|
||
if (scope.row.IsHaveUploadFailed) {
|
||
uploadQueues.forEach((v) => {
|
||
if (
|
||
v.dicomInfo.studyUid === scope.row.StudyInstanceUid &&
|
||
v.uploadState.record &&
|
||
v.uploadState.record.Failed.length
|
||
) {
|
||
r = true
|
||
}
|
||
})
|
||
}
|
||
return r
|
||
})()
|
||
">
|
||
<div slot="content">
|
||
{{ $t('trials:uploadDicomList:table:status4') }}
|
||
</div>
|
||
<span class="el-icon-warning" style="color: #cbb024; cursor: pointer"
|
||
v-if="scope.row.IsHaveUploadFailed"></span>
|
||
</el-tooltip>
|
||
<el-tooltip placement="top" v-if="!scope.row.IsCompleteClinicalData">
|
||
<div slot="content">
|
||
{{ $t('trials:crc-upload:confirm:message') }}
|
||
</div>
|
||
<span class="el-icon-warning" style="color: red; cursor: pointer"></span>
|
||
</el-tooltip>
|
||
{{ scope.row.StudyCode }}
|
||
</template>
|
||
</el-table-column>
|
||
<!-- 检查名称 -->
|
||
<el-table-column v-if="relationInfo.IsShowStudyName" prop="StudyName" :label="$t('trials:audit:table:StudyName')"
|
||
sortable />
|
||
<!-- 检查类型 -->
|
||
<el-table-column prop="ModalityForEdit" :label="$t('trials:audit:table:modality')" sortable />
|
||
<!-- 检查设备 -->
|
||
<el-table-column prop="Modalities" :label="$t('trials:audit:table:modality1')" sortable />
|
||
<!-- 检查部位 -->
|
||
<el-table-column prop="BodyPartForEdit" :label="$t('trials:uploadedDicoms:table:bodyPart')" min-width="100"
|
||
show-overflow-tooltip sortable>
|
||
<template slot-scope="scope">
|
||
{{ getBodyPart(scope.row.BodyPartForEdit) }}
|
||
</template>
|
||
</el-table-column>
|
||
<!-- 序列数量 -->
|
||
<el-table-column prop="SeriesCount" :label="$t('trials:uploadedDicoms:table:seriesCount')" min-width="100"
|
||
show-overflow-tooltip sortable />
|
||
<!-- 图像数量 -->
|
||
<el-table-column prop="InstanceCount" :label="$t('trials:uploadedDicoms:table:instanceCount')" min-width="100"
|
||
show-overflow-tooltip sortable />
|
||
<!-- 检查日期 -->
|
||
<el-table-column prop="StudyTime" :label="$t('trials:uploadedDicoms:table:studyDate')" min-width="120"
|
||
show-overflow-tooltip sortable>
|
||
<template slot-scope="scope">
|
||
{{
|
||
scope.row.StudyTime
|
||
? moment(scope.row.StudyTime).format('YYYY-MM-DD')
|
||
: ''
|
||
}}
|
||
</template>
|
||
</el-table-column>
|
||
<!-- 更新时间 -->
|
||
<el-table-column prop="UpdateTime" :label="$t('trials:uploadedDicoms:table:UpdateTime')" min-width="120"
|
||
show-overflow-tooltip sortable />
|
||
<!-- 上传时间 -->
|
||
<el-table-column prop="UploadedTime" :label="$t('trials:uploadedDicoms:table:uploadedTime')" min-width="120"
|
||
show-overflow-tooltip sortable />
|
||
<el-table-column :label="$t('common:action:action')" min-width="260" fixed="right">
|
||
<template slot-scope="scope">
|
||
<!-- 预览 -->
|
||
<el-button icon="el-icon-view" :disabled="scope.row.SeriesCount === 0"
|
||
:title="$t('trials:uploadedDicoms:action:preview')" circle @click="handleViewStudy(scope.row)" />
|
||
<!-- 上传临床数据 -->
|
||
<el-button icon="el-icon-upload2" v-if="
|
||
['PT、CT', 'CT、PT', 'PET-CT'].includes(scope.row.Modalities) &&
|
||
relationInfo.IsHaveStudyClinicalData
|
||
" :title="$t('trials:workbench:title:UploadClinicalData')" circle @click="handleUploadPetData(scope.row)" />
|
||
<!-- 编辑 -->
|
||
<el-button icon="el-icon-edit-outline" v-hasPermi="['trials:trials-panel:visit:crc-upload:edit']"
|
||
:title="$t('common:button:edit')" circle @click="handleEditStudy(scope.row)" />
|
||
<!-- 删除 :disabled="scope.row.IsDeleted"-->
|
||
<el-button icon="el-icon-delete" :title="$t('trials:uploadedDicoms:action:delete')" circle
|
||
@click="handleDeleteStudy(scope.row)" />
|
||
<!-- <el-button-->
|
||
<!-- icon="el-icon-toilet-paper"-->
|
||
<!-- circle-->
|
||
<!-- :title="$t('trials:uploadDicomFiles:button:historical')"-->
|
||
<!-- @click="handleHistorical(scope.row)"-->
|
||
<!-- />-->
|
||
</template>
|
||
</el-table-column>
|
||
</el-table>
|
||
<!-- 多文件上传 -->
|
||
<!-- <el-divider content-position="left">{{
|
||
$t('trials:uploadedDicoms:title:dicomFilesOnly')
|
||
}}</el-divider> -->
|
||
<div style="margin: 30px 0 10px 0">
|
||
{{ $t('trials:uploadedDicoms:title:dicomFilesOnly') }}
|
||
</div>
|
||
<el-tabs v-model="uploadActiveName">
|
||
<!-- 本地上传 -->
|
||
<el-tab-pane :label="$t('trials:uploadedDicoms:tab:uploadFile')" name="file">
|
||
<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="small">{{
|
||
$t('trials:uploadedDicomsicom:button:selectFolder')
|
||
}}</el-button>
|
||
<input type="file" name="file" ref="pathClear" :disabled="btnLoading" webkitdirectory multiple title=""
|
||
@change="beginScanFiles($event)" />
|
||
</div>
|
||
</div>
|
||
</form>
|
||
|
||
<!-- 文件列表 -->
|
||
<el-table ref="dicomFilesTable" :data="uploadQueues" :row-key="(row) => row.studyIndex" 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-start">
|
||
<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>
|
||
<!--:percentage="
|
||
(scope.row.dicomInfo.failedFileCount * 100) /
|
||
scope.row.dicomInfo.fileCount
|
||
"
|
||
:show-text="false"--->
|
||
<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(3)
|
||
}}MB/{{
|
||
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
|
||
}}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-column v-show="isScan" :label="$t('common:action:action')" width="200">
|
||
<template slot-scope="scope">
|
||
<!-- 预览 -->
|
||
<!-- :disabled="scope.row.dicomInfo.failedFileCount < scope.row.dicomInfo.fileCount && scope.row.dicomInfo.failedFileCount !== 0"-->
|
||
<el-button icon="el-icon-view" circle :disabled="(scope.row.uploadState.stateCode !== '' &&
|
||
scope.row.dicomInfo.failedFileCount <
|
||
scope.row.dicomInfo.fileCount &&
|
||
!scope.row.uploadState.record) ||
|
||
btnLoading
|
||
" :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 !== '' &&
|
||
scope.row.dicomInfo.failedFileCount <
|
||
scope.row.dicomInfo.fileCount &&
|
||
!scope.row.uploadState.record) ||
|
||
btnLoading
|
||
" @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> -->
|
||
<span style="margin-right: 10px">{{
|
||
$store.state.trials.uploadTip
|
||
}}</span>
|
||
<!-- 上传 -->
|
||
<el-button size="small" type="primary" :disabled="selectArr.length == 0 || !isScan" :loading="btnLoading"
|
||
@click="beginUploadQueues">
|
||
{{ $t('trials:uploadDicomList:button:upload') }}
|
||
</el-button>
|
||
</div>
|
||
</el-tab-pane>
|
||
<!-- pacs上传 -->
|
||
<el-tab-pane :label="$t('trials:uploadNonDicoms:tab:uploadPacs')" name="pacs" :disabled="btnLoading"
|
||
v-if="relationInfo.IsPacsConnectConfiged">
|
||
<uploadDicomPacs v-if="uploadActiveName === 'pacs'" ref="dicomPacs" :subjectVisitId="subjectVisitId"
|
||
:relationInfo="relationInfo" :subjectId="subjectId" @getList="getParentList" @petDataTip="petDataTip" />
|
||
</el-tab-pane>
|
||
</el-tabs>
|
||
<!-- 预览影像模态框 -->
|
||
<el-dialog v-if="previewVisible" :fullscreen="true" :show-close="true" :visible.sync="previewVisible"
|
||
append-to-body>
|
||
<DicomPreview :uid="uid" :studyList="uploadQueues" />
|
||
</el-dialog>
|
||
<!--pet-ct临床数据上传-->
|
||
<el-dialog v-if="petVisible" :show-close="true" :visible.sync="petVisible" append-to-body>
|
||
<uploadPetClinicalData :subject-visit-id="data.Id" :data="data" :studyData="studyData" :allow-add-or-edit="true"
|
||
@getStudyInfo="getStudyInfo" />
|
||
</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>
|
||
<el-dialog v-if="editStudyInfoVisible" :title="$t('trials:audit:action:edit')" :visible.sync="editStudyInfoVisible"
|
||
:close-on-click-modal="false" append-to-body custom-class="base-dialog-wrapper" width="600px">
|
||
<div style="
|
||
padding: 10px;
|
||
border: 1px solid #e0e0e0;
|
||
max-height: 650px;
|
||
overflow-y: auto;
|
||
">
|
||
<el-form ref="studyForm" :model="studyForm" label-width="100px">
|
||
<!-- 检查编号 -->
|
||
<el-form-item :label="$t('trials:audit:table:studyId')">
|
||
<el-input v-model="studyForm.StudyCode" disabled />
|
||
</el-form-item>
|
||
<!-- 检查名称 -->
|
||
<el-form-item v-if="relationInfo.IsShowStudyName" :label="$t('trials:audit:table:StudyName')" prop="StudyName"
|
||
:rules="[
|
||
{
|
||
required: true,
|
||
message: $t('common:ruleMessage:specify'),
|
||
trigger: 'blur',
|
||
},
|
||
]">
|
||
<el-radio-group v-model="studyForm.StudyName">
|
||
<template v-for="m in relationInfo.StudyNameList">
|
||
<el-radio v-if="m.IsChoose" :key="m.Name" :label="isEN ? m.EnName : m.Name"
|
||
style="margin-bottom: 15px" />
|
||
</template>
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<!-- 检查类型 -->
|
||
<el-form-item v-if="studyForm.IsDicomData" :label="$t('trials:audit:table:modality')">
|
||
<el-input v-model="studyForm.Modalities" disabled />
|
||
</el-form-item>
|
||
<!-- 检查类型 -->
|
||
<el-form-item v-else :label="$t('trials:audit:table:modality')" prop="Modalities" :rules="[
|
||
{
|
||
required: true,
|
||
message: $t('common:ruleMessage:specify'),
|
||
trigger: 'blur',
|
||
},
|
||
]">
|
||
<el-radio-group v-model="studyForm.Modality">
|
||
<el-radio v-for="m in trialModalitys" v-show="m !== ''" :key="m" :label="m" style="margin-bottom: 15px" />
|
||
</el-radio-group>
|
||
</el-form-item>
|
||
<!-- 检查部位 -->
|
||
<el-form-item :label="$t('trials:audit:table:bodyPart')" prop="BodyPartForEdit" :rules="[
|
||
{
|
||
required: true,
|
||
message: $t('common:ruleMessage:specify'),
|
||
trigger: 'blur',
|
||
},
|
||
]">
|
||
<el-checkbox-group v-model="studyForm.BodyPartForEdit">
|
||
<el-checkbox v-for="bodyPart in trialBodyPartTypes" :key="bodyPart" :label="bodyPart">{{
|
||
$fd('Bodypart', bodyPart, 'Code', BodyPart, 'Name')
|
||
}}</el-checkbox>
|
||
</el-checkbox-group>
|
||
</el-form-item>
|
||
<!-- 序列数量 -->
|
||
<el-form-item :label="$t('trials:audit:table:seriesCount')">
|
||
<el-input v-model="studyForm.SeriesCount" disabled />
|
||
</el-form-item>
|
||
<!-- 图像数量 -->
|
||
<el-form-item v-if="studyForm.InstanceCount" :label="$t('trials:audit:table:instanceCount')">
|
||
<el-input v-model="studyForm.InstanceCount" disabled />
|
||
</el-form-item>
|
||
<!-- 检查日期 -->
|
||
<el-form-item :label="$t('trials:audit:table:studyDate')">
|
||
<el-date-picker v-model="studyForm.StudyTime" disabled type="date" value-format="yyyy-MM-dd"
|
||
format="yyyy-MM-dd" style="width: 100%" />
|
||
</el-form-item>
|
||
</el-form>
|
||
</div>
|
||
<div slot="footer" class="dialog-footer">
|
||
<el-button :disabled="btnLoading" size="small" type="primary" @click="editStudyInfoVisible = false">
|
||
{{ $t('common:button:cancel') }}
|
||
</el-button>
|
||
<el-button :loading="btnLoading" size="small" type="primary" @click="handleUpdateStudyInfo">
|
||
{{ $t('common:button:save') }}
|
||
</el-button>
|
||
</div>
|
||
</el-dialog>
|
||
</div>
|
||
</template>
|
||
<script>
|
||
import {
|
||
dicomUploadInProgress,
|
||
batchVerifyStudyAllowUpload,
|
||
getSubjectVisitUploadedStudyList,
|
||
deleteStudyList,
|
||
updateModality,
|
||
preArchiveDicomStudy,
|
||
addOrUpdateArchiveStudy,
|
||
} from '@/api/trials'
|
||
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 DicomPreview from '@/views/dicom-show/dicom-preview'
|
||
import uploadPetClinicalData from './uploadPetClinicalData.vue'
|
||
import dicomStore from '@/utils/dicom-store'
|
||
import { getToken } from '@/utils/auth'
|
||
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
|
||
import { convertBytes } from '@/utils/dicom-character-set'
|
||
import moment from 'moment'
|
||
import store from '@/store'
|
||
import uploadDicomPacs from './uploadDiocmPacs.vue'
|
||
export default {
|
||
name: 'UploadDicomFiles',
|
||
components: { DicomPreview, uploadPetClinicalData, uploadDicomPacs },
|
||
props: {
|
||
data: {
|
||
type: Object,
|
||
default() {
|
||
return {}
|
||
},
|
||
},
|
||
subjectVisitId: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
subjectId: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
activeName: {
|
||
type: String,
|
||
required: true,
|
||
},
|
||
},
|
||
data() {
|
||
return {
|
||
uploadActiveName: 'file',
|
||
editStudyInfoVisible: false,
|
||
studyForm: {
|
||
StudyCode: '',
|
||
IsDicomData: true,
|
||
Modalities: '',
|
||
BodyPartForEdit: [],
|
||
SeriesCount: null,
|
||
StudyTime: '',
|
||
},
|
||
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: [],
|
||
relationInfo: {},
|
||
trialBodyPartTypes: [],
|
||
trialModalitys: [],
|
||
myInterval: [],
|
||
studyErrorList: [],
|
||
confirmFlag: false,
|
||
|
||
// pet-ct临床数据上传
|
||
petVisible: false,
|
||
studyData: [],
|
||
BodyPart: {},
|
||
|
||
isClose: false,
|
||
}
|
||
},
|
||
computed: {
|
||
isEN() {
|
||
return this.$i18n.locale !== 'zh'
|
||
},
|
||
},
|
||
watch: {
|
||
btnLoading() {
|
||
store.dispatch('trials/setUnLock', this.btnLoading)
|
||
},
|
||
},
|
||
async mounted() {
|
||
this.trialId = this.$route.query.trialId
|
||
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
|
||
if (Object.keys(this.data).length) {
|
||
this.form = { ...this.data }
|
||
}
|
||
this.getStudyInfo()
|
||
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: {
|
||
getParentList() {
|
||
this.getStudyInfo()
|
||
this.$emit('getList')
|
||
},
|
||
handleHistorical(row) {
|
||
this.$router.push(
|
||
`/trials/trials-panel/trial-summary/upload-monitor?trialId=${this.trialId}&trialCode=${this.$route.query.trialCode}&${this.$route.query.researchProgramNo}&studyCode=${row.StudyCode}`
|
||
)
|
||
},
|
||
// 打开检查信息编辑框
|
||
handleEditStudy(row) {
|
||
this.editStudyInfoVisible = true
|
||
this.studyForm = { ...row }
|
||
var bodyPart = []
|
||
if (this.studyForm.BodyPartForEdit.indexOf('|') !== -1) {
|
||
bodyPart = this.studyForm.BodyPartForEdit.split('|')
|
||
} else if (this.studyForm.BodyPartForEdit !== '') {
|
||
bodyPart.push(this.studyForm.BodyPartForEdit)
|
||
}
|
||
this.$set(this.studyForm, 'Modality', row.ModalityForEdit)
|
||
this.studyForm.BodyPartForEdit = bodyPart
|
||
},
|
||
// 更新拍片部位/拍片类型信息
|
||
handleUpdateStudyInfo() {
|
||
this.$refs['studyForm'].validate((valid) => {
|
||
if (!valid) return
|
||
this.btnLoading = true
|
||
this.studyForm.BodyPart = this.studyForm.BodyPartForEdit.join('|')
|
||
// this.studyForm.Modality = this.studyForm.Modalities
|
||
var params = {
|
||
id: this.studyForm.StudyId,
|
||
subjectVisitId: this.data.Id,
|
||
type: 1,
|
||
modality: this.studyForm.Modality,
|
||
bodyPart: this.studyForm.BodyPart,
|
||
StudyName: this.studyForm.StudyName,
|
||
}
|
||
updateModality(this.trialId, params)
|
||
.then((res) => {
|
||
this.btnLoading = false
|
||
if (res.IsSuccess) {
|
||
this.getStudyInfo()
|
||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||
this.editStudyInfoVisible = false
|
||
}
|
||
})
|
||
.catch(() => {
|
||
this.btnLoading = false
|
||
})
|
||
})
|
||
},
|
||
format(v) {
|
||
return v
|
||
},
|
||
// 获取已上传的dicom影像
|
||
getStudyInfo() {
|
||
this.studyLoading = true
|
||
getSubjectVisitUploadedStudyList(this.subjectVisitId)
|
||
.then((res) => {
|
||
// this.studyList = res.Result
|
||
this.relationInfo = res.OtherInfo
|
||
this.trialBodyPartTypes = this.relationInfo.BodyPartTypes
|
||
? this.relationInfo.BodyPartTypes.split('|')
|
||
: []
|
||
this.trialModalitys = this.relationInfo.Modalitys
|
||
? this.relationInfo.Modalitys.split('|')
|
||
: []
|
||
this.studyLoading = false
|
||
this.studyList = res.Result
|
||
})
|
||
.catch(() => {
|
||
this.studyLoading = false
|
||
})
|
||
},
|
||
// 弹框提示pet-ct临床数据未上传
|
||
petDataTip(isPacs = false) {
|
||
if (this.confirmFlag || isPacs) {
|
||
this.confirmFlag = false
|
||
this.$confirm(
|
||
this.$t('trials:crc-upload:confirm:message'),
|
||
this.$t('trials:uploadDicomList:label:prompt'),
|
||
{
|
||
confirmButtonText: this.$t('trials:reviewTrack:impactList:save'),
|
||
// cancelButtonText: this.$t("common:button:cancel"),
|
||
type: 'warning',
|
||
showCancelButton: false,
|
||
}
|
||
)
|
||
.then(() => {
|
||
this.confirmFlag = false
|
||
})
|
||
.catch(() => {
|
||
this.confirmFlag = 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')
|
||
},
|
||
// 打开上传pet临床数据弹框
|
||
handleUploadPetData(row) {
|
||
this.studyData = row
|
||
this.studyData.SubjectId = this.subjectId
|
||
this.petVisible = true
|
||
},
|
||
// 预览所有影像
|
||
handlePreviewAllFiles() {
|
||
var token = getToken()
|
||
if (this.$route.path === '/trials/trials-panel/visit/crc-question') {
|
||
var routeData = this.$router.resolve({
|
||
path: `/showvisitdicoms?trialId=${this.trialId}&visitInfo=${this.data.VisitName}(${this.data.VisitNum})&subjectVisitId=${this.data.SubjectVisitId}&isFromCRCUpload=1&TokenKey=${token}`,
|
||
})
|
||
} else {
|
||
var routeData = this.$router.resolve({
|
||
path: `/showvisitdicoms?trialId=${this.trialId}&visitInfo=${this.data.VisitName}(${this.data.VisitNum})&subjectVisitId=${this.data.Id}&isFromCRCUpload=1&TokenKey=${token}`,
|
||
})
|
||
}
|
||
window.open(routeData.href, '_blank')
|
||
},
|
||
// 扫描待上传文件
|
||
beginScanFiles(e) {
|
||
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')
|
||
)
|
||
var scope = this
|
||
scope.scanState = ''
|
||
scope.isScan = false
|
||
var p = new Promise(function (resolve) {
|
||
resolve()
|
||
})
|
||
var validFilesCount = 0
|
||
for (var i = 0; i < files.length; ++i) {
|
||
; (function (index) {
|
||
p = p.then(function () {
|
||
if (files[index].name.toUpperCase().indexOf('DICOMDIR') === -1) {
|
||
validFilesCount = validFilesCount + 1
|
||
return scope.parseDicomFile(files[index])
|
||
}
|
||
})
|
||
})(i)
|
||
}
|
||
p.then(function (result) {
|
||
scope.uploadQueues.forEach((v, i) => {
|
||
scope.$refs.dicomFilesTable.toggleRowSelection(v, true)
|
||
})
|
||
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 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
|
||
)
|
||
// 解析dicom中字符集字段与解析库不一致 2025.03.04
|
||
let SpecificCharacterSet = data.string('x00080005')
|
||
? data.string('x00080005').replace('ISO IR', 'ISO_IR')
|
||
: ''
|
||
const patientNameStr = convertBytes(
|
||
SpecificCharacterSet,
|
||
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,
|
||
},
|
||
|
||
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
|
||
)
|
||
let SpecificCharacterSet = data.string('x00080005')
|
||
? data.string('x00080005').replace('ISO IR', 'ISO_IR')
|
||
: ''
|
||
const seriesDescriptionStr = convertBytes(
|
||
SpecificCharacterSet,
|
||
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)
|
||
}
|
||
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
|
||
)
|
||
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,
|
||
})
|
||
}
|
||
},
|
||
// 校验该检查是否上传过
|
||
verifyStudy() {
|
||
this.btnLoading = true
|
||
var studyList = []
|
||
this.selectArr.forEach((item) => {
|
||
item.dicomInfo.uploadFileSize = 0
|
||
if (!item.uploadState.selected) {
|
||
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(async (res) => {
|
||
var messageArr = []
|
||
res.Result.forEach((item) => {
|
||
const i = this.uploadQueues.findIndex(
|
||
(value) => value.dicomInfo.studyUid === item.StudyInstanceUid
|
||
)
|
||
let instanceUidList = []
|
||
item.UploadedSeriesList.forEach((v) => {
|
||
v.SOPInstanceUIDList.forEach((v1) => {
|
||
instanceUidList.push(v1)
|
||
})
|
||
})
|
||
// isReUploadinstanceUidList1.includes(instanceUidList2)
|
||
try {
|
||
this.uploadQueues[i].seriesList.forEach((v) => {
|
||
let o = item.UploadedSeriesList.find((v1) => {
|
||
return v.seriesUid === v1.SeriesId
|
||
// v.instanceList.forEach(v2 => {
|
||
// let o2 = v1.SOPInstanceUIDList.find(v3 => {
|
||
// return v3 === v2.instanceUid
|
||
// })
|
||
// if (!!o2) {
|
||
// v2.isReUpload = true
|
||
// }
|
||
// })
|
||
})
|
||
if (!!o) {
|
||
v.isReUpload = true
|
||
}
|
||
})
|
||
this.uploadQueues[i].seriesList.forEach((v) => {
|
||
v.instanceList.forEach((v2) => {
|
||
let o2 = instanceUidList.find((v3) => {
|
||
return v3 === v2.instanceUid
|
||
})
|
||
if (!!o2) {
|
||
v2.isReUpload = true
|
||
}
|
||
})
|
||
})
|
||
} catch (e) {
|
||
console.log(e)
|
||
}
|
||
// 不能上传或不能重传时,收集校验结果提示,并取消勾选,设置上传状态
|
||
if (item.ErrorMesseage) {
|
||
this.uploadQueues[i].uploadState.AllowReUpload =
|
||
item.AllowReUpload
|
||
this.$refs.dicomFilesTable.toggleRowSelection(
|
||
this.uploadQueues[i]
|
||
)
|
||
this.uploadQueues[i].uploadState.selected = true
|
||
const msg = `${item.ErrorMesseage}`
|
||
messageArr.push(msg)
|
||
}
|
||
|
||
// 可以重传时,记录需要被覆盖的检查ID
|
||
if (item.AllowReUpload) {
|
||
this.uploadQueues[i].AbandonStudyId = item.StudyInfo
|
||
? item.StudyInfo.Id
|
||
: ''
|
||
}
|
||
this.uploadQueues[i].uploadState.AllowReUpload = item.AllowReUpload
|
||
})
|
||
|
||
if (messageArr.length > 0) {
|
||
var li = messageArr.map((msg) => {
|
||
return `<li>${msg}</li>`
|
||
})
|
||
const content = `
|
||
<div>
|
||
<ol>
|
||
${li.join('')}
|
||
</ol>
|
||
</div>`
|
||
this.$alert(content, '', {
|
||
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
|
||
if (!this.uploadQueues[index].uploadState.selected) {
|
||
await this.archiveStudy(index, res.OtherInfo)
|
||
}
|
||
}
|
||
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.btnLoading = false
|
||
// console.log(11111);
|
||
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()
|
||
})
|
||
}
|
||
if (this.confirmFlag) {
|
||
this.petDataTip()
|
||
}
|
||
})
|
||
})
|
||
.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
|
||
}, '')
|
||
},
|
||
canvasToBlob(canvas) {
|
||
return new Promise((resolve) => {
|
||
canvas.toBlob((blob) => {
|
||
resolve(blob)
|
||
})
|
||
})
|
||
},
|
||
dicomToPng(imageId, width, height) {
|
||
return new Promise((resolve) => {
|
||
cornerstone.loadImage(imageId).then(async (image) => {
|
||
let canvas = document.createElement('canvas')
|
||
canvas.width = (width * 60) / height
|
||
canvas.height = 60
|
||
if (image) {
|
||
cornerstone.renderToCanvas(canvas, image)
|
||
// 将 Canvas 图像对象转换为 PNG 格式
|
||
let blob = await this.canvasToBlob(canvas)
|
||
resolve(blob)
|
||
} else {
|
||
resolve()
|
||
}
|
||
})
|
||
}).catch((reason) => {
|
||
reason()
|
||
})
|
||
},
|
||
// 上传影像并归档
|
||
archiveStudy(index, config) {
|
||
var scope = this
|
||
return new Promise(function (resolve, reject) {
|
||
try {
|
||
preArchiveDicomStudy({
|
||
trialId: scope.trialId,
|
||
trialSiteId: scope.data.TrialSiteId,
|
||
subjectId: scope.subjectId,
|
||
subjectVisitId: scope.subjectVisitId,
|
||
// failedFileCount: scope.uploadQueues[index].dicomInfo.failedFileCount,
|
||
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
|
||
let fileList = scope.uploadQueues[index].fileList
|
||
dicomInfo.seriesNum = seriesNum
|
||
dicomInfo.fileNum = fileNum
|
||
dicomInfo.trialSiteId = scope.data.TrialSiteId
|
||
dicomInfo.subjectId = scope.data.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,
|
||
trialSiteId: scope.data.TrialSiteId,
|
||
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: config.DicomStoreInfo.SubjectCode,
|
||
patientName: '',
|
||
patientAge: '',
|
||
patientSex: config.DicomStoreInfo.SubjectSex,
|
||
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.studyUid
|
||
}/${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,
|
||
},
|
||
config,
|
||
(percentage, checkpoint, lastPer) => {
|
||
dicomInfo.uploadFileSize +=
|
||
checkpoint.size * (percentage - lastPer)
|
||
if (
|
||
dicomInfo.uploadFileSize > dicomInfo.fileSize
|
||
) {
|
||
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
||
}
|
||
if (
|
||
Math.abs(dicomInfo.uploadFileSize - dicomInfo.fileSize) < 5000
|
||
) {
|
||
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.studyUid}/${v.seriesUid}.jpg`
|
||
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.trialSiteId}/${params.subjectId}/${params.subjectVisitId}/${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}.jpg`
|
||
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)
|
||
addOrUpdateArchiveStudy(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
|
||
let flag =
|
||
res.Result === 'PET-CT' ||
|
||
res.Result === 'CT、PT' ||
|
||
res.Result === 'PT、CT'
|
||
// let flag = params.study.seriesList.some(item=>item.modality==='PT');
|
||
if (flag && scope.relationInfo.IsHaveStudyClinicalData) {
|
||
scope.confirmFlag = true
|
||
}
|
||
scope.getStudyInfo()
|
||
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(() => {
|
||
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()
|
||
}
|
||
})
|
||
},
|
||
generateTxtFile(text) {
|
||
let blob = new Blob(['\ufeff', text], { type: 'text/plain' })
|
||
return blob
|
||
},
|
||
// 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.uploadQueues.splice(index, 1)
|
||
this.uploadQueues.forEach((v, i) => {
|
||
if (v.uploadState.record) {
|
||
v.uploadState.selected = false
|
||
this.$refs.dicomFilesTable.toggleRowSelection(v, true)
|
||
}
|
||
v.studyIndex = i
|
||
})
|
||
this.handleSelectionChange(this.uploadQueues)
|
||
})
|
||
},
|
||
// 当选择项发生变化时收集待上传文件数据
|
||
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
|
||
}
|
||
},
|
||
// 收集已上传文件列表勾选项
|
||
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()
|
||
if (
|
||
this.$route.path !== '/trials/trials-panel/visit/crc-question'
|
||
) {
|
||
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()
|
||
if (this.uploadActiveName === 'pacs') {
|
||
this.$refs.dicomPacs.getList()
|
||
}
|
||
if (
|
||
this.$route.path !== '/trials/trials-panel/visit/crc-question'
|
||
) {
|
||
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 ''
|
||
}
|
||
},
|
||
getBodyPart(bodyPart) {
|
||
if (!bodyPart) return ''
|
||
var separator = ','
|
||
if (bodyPart.indexOf('|') > -1) {
|
||
separator = '|'
|
||
} else if (bodyPart.indexOf(',') > -1) {
|
||
separator = ','
|
||
} else if (bodyPart.indexOf(',') > -1) {
|
||
separator = ','
|
||
}
|
||
var arr = bodyPart.split(separator)
|
||
var newArr = arr.map((i) => {
|
||
return this.$fd('Bodypart', i.trim(), 'Code', this.BodyPart, 'Name')
|
||
})
|
||
return newArr.join(' | ')
|
||
},
|
||
},
|
||
}
|
||
</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: #428bca;
|
||
}
|
||
|
||
#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>
|