【LiLi】支持影像拖拽上传
continuous-integration/drone/push Build is passing Details

main
wangxiaoshuang 2025-11-05 16:33:03 +08:00
parent 4f5fb17bb8
commit 6c02793d2f
5 changed files with 492 additions and 350 deletions

View File

@ -197,3 +197,29 @@ export function workSpeedclose(isForce = false) {
imageId = null; imageId = null;
percentageById = {}; percentageById = {};
} }
export async function readEntry(entry) {
const files = [];
// 如果是文件夹,创建读取器并递归读取其内容
if (entry.isDirectory) {
const directoryReader = entry.createReader();
const entries = await new Promise((resolve, reject) => {
directoryReader.readEntries(resolve, reject); // readEntries是异步的
});
// 递归读取文件夹内的每一项
for (const subEntry of entries) {
const subFiles = await readEntry(subEntry);
files.push(...subFiles);
}
}
// 如果是文件则将其转换为File对象
else if (entry.isFile) {
const file = await new Promise((resolve, reject) => {
entry.file(resolve, reject); // entry.file()是异步的
});
files.push(file);
}
return files;
}

View File

@ -30,49 +30,52 @@
</div> </div>
</div> </div>
</form> </form>
<!-- 文件列表 --> <div class="drag" ref="drag" @dragover="handleDragover" @drop="handleDrop">
<el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300" <!-- 文件列表 -->
@selection-change="handleSelectionChange"> <el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300"
<el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !loading" /> @selection-change="handleSelectionChange">
<el-table-column type="index" width="50" /> <el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !loading" />
<!-- 文件名称 --> <el-table-column type="index" width="50" />
<el-table-column prop="name" :label="$t('trials:trialDocument:table:fileName')" min-width="100" /> <!-- 文件名称 -->
<!-- 文件大小 --> <el-table-column prop="name" :label="$t('trials:trialDocument:table:fileName')" min-width="100" />
<el-table-column prop="size" :label="$t('trials:trialDocument:table:fileSize')"> <!-- 文件大小 -->
<template slot-scope="scope"> <el-table-column prop="size" :label="$t('trials:trialDocument:table:fileSize')">
<span>{{ <template slot-scope="scope">
scope.row.size && scope.row.size > 0 <span>{{
? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB` scope.row.size && scope.row.size > 0
: '0MB' ? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB`
}}</span> : '0MB'
</template> }}</span>
</el-table-column> </template>
<!-- 文件类型 --> </el-table-column>
<el-table-column prop="type" :label="$t('trials:trialDocument:table:fileType')" /> <!-- 文件类型 -->
<!-- 上传状态 --> <el-table-column prop="type" :label="$t('trials:trialDocument:table:fileType')" />
<el-table-column prop="status" :label="$t('trials:trialDocument:table:uploadStatus')" min-width="100"> <!-- 上传状态 -->
<template slot-scope="scope"> <el-table-column prop="status" :label="$t('trials:trialDocument:table:uploadStatus')" min-width="100">
<el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]" <template slot-scope="scope">
v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }} <el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]"
</el-tag> v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
</template> </el-tag>
</el-table-column> </template>
<el-table-column :label="$t('trials:trialDocument:table:failedFileCount')" min-width="150" </el-table-column>
show-overflow-tooltip> <el-table-column :label="$t('trials:trialDocument:table:failedFileCount')" min-width="150"
<template slot-scope="scope"> show-overflow-tooltip>
<el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) * <template slot-scope="scope">
1 <el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
: ((scope.row.uploadFileSize * 100) / 1).toFixed(2) * 1
1" /> : ((scope.row.uploadFileSize * 100) / 1).toFixed(2) *
</template> 1" />
</el-table-column> </template>
<el-table-column :label="$t('common:action:action')"> </el-table-column>
<template slot-scope="scope"> <el-table-column :label="$t('common:action:action')">
<el-button size="mini" icon="el-icon-delete" circle :disabled="loading" <template slot-scope="scope">
:title="$t('trials:trialDocument:action:delete')" @click="handleRemoveFile(scope.row)" /> <el-button size="mini" icon="el-icon-delete" circle :disabled="loading"
</template> :title="$t('trials:trialDocument:action:delete')" @click="handleRemoveFile(scope.row)" />
</el-table-column> </template>
</el-table> </el-table-column>
</el-table>
</div>
</div> </div>
<div slot="dialog-footer"> <div slot="dialog-footer">
<div style="text-align: right; padding: 10px 0px"> <div style="text-align: right; padding: 10px 0px">
@ -91,6 +94,7 @@
import baseModel from '@/components/BaseModel' import baseModel from '@/components/BaseModel'
import { deepClone } from '@/utils/index.js' import { deepClone } from '@/utils/index.js'
import store from '@/store' import store from '@/store'
import { readEntry } from '@/utils/index'
export default { export default {
name: 'uploadFiles', name: 'uploadFiles',
props: { props: {
@ -131,16 +135,41 @@ export default {
} }
}, },
methods: { methods: {
handleDragover(e) {
e.stopPropagation();
e.preventDefault();
},
handleDrop(e) {
e.stopPropagation();
e.preventDefault();
this.beginScanFiles(e, true)
},
// //
handleSelectionChange(selection) { handleSelectionChange(selection) {
this.selectArr = selection this.selectArr = selection
}, },
// //
beginScanFiles(e) { async beginScanFiles(e, isDrop = false) {
if (this.fileInput) { if (this.fileInput) {
this.fileInput = null this.fileInput = null
} }
var files = [...e.target.files] var files = []
if (isDrop) {
const items = e.dataTransfer.items;
const allFiles = []; //
//
for (const item of items) {
const entry = item.webkitGetAsEntry(); //
if (entry) {
const files = await readEntry(entry); //
allFiles.push(...files);
}
}
files = allFiles
} else {
files = [...e.target.files]
}
if (this.limitLength && this.fileList.length >= this.limitLength) if (this.limitLength && this.fileList.length >= this.limitLength)
return this.$message.warning( return this.$message.warning(
this.$t('trials:trialDocument:message:limitLength') this.$t('trials:trialDocument:message:limitLength')

View File

@ -2,8 +2,8 @@
<div v-loading="loading" class="clinical-data-wrapper"> <div v-loading="loading" class="clinical-data-wrapper">
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane v-for="cd in clinicalDatas" :key="cd.ClinicalDataTrialSetId" :label="$i18n.locale === 'zh' <el-tab-pane v-for="cd in clinicalDatas" :key="cd.ClinicalDataTrialSetId" :label="$i18n.locale === 'zh'
? cd.ClinicalDataSetName ? cd.ClinicalDataSetName
: cd.ClinicalDataSetEnName : cd.ClinicalDataSetEnName
"> ">
<!-- 格式化录入 --> <!-- 格式化录入 -->
<div v-if="cd.ClinicalUploadType === 0"> <div v-if="cd.ClinicalUploadType === 0">
@ -180,32 +180,36 @@
" /> " />
</div> </div>
</div> </div>
<el-table :data="cd.PDFFileList" style="width: 100%"> <div class="drag" ref="drag" @dragover="handleDragover"
<el-table-column type="index" width="50" /> @drop="(e) => handleDrop(e, cd.Id, cd.ClinicalDataTrialSetId)">
<!-- 文件名称 --> <el-table :data="cd.PDFFileList" style="width: 100%">
<el-table-column prop="FileName" :label="$t('trials:uploadClinicalData:table:fileName')" width="250" /> <el-table-column type="index" width="50" />
<!-- 文件大小 --> <!-- 文件名称 -->
<el-table-column prop="Size" :label="$t('trials:uploadClinicalData:table:fileSize')" width="150"> <el-table-column prop="FileName" :label="$t('trials:uploadClinicalData:table:fileName')" width="250" />
<template slot-scope="scope"> <!-- 文件大小 -->
<span>{{ <el-table-column prop="Size" :label="$t('trials:uploadClinicalData:table:fileSize')" width="150">
$FormatSize(scope.row.Size) <template slot-scope="scope">
<span>{{
$FormatSize(scope.row.Size)
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<!-- 上传时间 --> <!-- 上传时间 -->
<el-table-column prop="CreateTime" :label="$t('trials:uploadClinicalData:table:uploadedTime')" <el-table-column prop="CreateTime" :label="$t('trials:uploadClinicalData:table:uploadedTime')"
width="200" /> width="200" />
<el-table-column :label="$t('common:action:action')" width="200"> <el-table-column :label="$t('common:action:action')" width="200">
<template slot-scope="scope"> <template slot-scope="scope">
<!-- 预览 --> <!-- 预览 -->
<el-button icon="el-icon-view" circle :title="$t('trials:uploadClinicalData:action:preview')" <el-button icon="el-icon-view" circle :title="$t('trials:uploadClinicalData:action:preview')"
size="small" @click.native.prevent="preview(scope.row)" /> size="small" @click.native.prevent="preview(scope.row)" />
<!-- 移除 --> <!-- 移除 -->
<el-button v-if="allowAddOrEdit" icon="el-icon-delete" circle :title="$t('common:button:delete')" <el-button v-if="allowAddOrEdit" icon="el-icon-delete" circle :title="$t('common:button:delete')"
size="small" @click.native.prevent="deleteFile(scope.row.Id)" /> size="small" @click.native.prevent="deleteFile(scope.row.Id)" />
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
</div>
</div> </div>
<!-- PDF录入 --> <!-- PDF录入 -->
<div v-if="cd.ClinicalUploadType === 2"> <div v-if="cd.ClinicalUploadType === 2">
@ -274,6 +278,7 @@ import PreviousFiles from "./previousFiles";
import clinicalDataQuestions from "@/components/clinicalDataQuestions"; import clinicalDataQuestions from "@/components/clinicalDataQuestions";
import PreviewFile from "@/components/PreviewFile/index"; import PreviewFile from "@/components/PreviewFile/index";
import moment from "moment"; import moment from "moment";
import { readEntry } from '@/utils/index'
export default { export default {
name: "ClinicalData", name: "ClinicalData",
components: { components: {
@ -333,14 +338,39 @@ export default {
this.getClinicalData(); this.getClinicalData();
}, },
methods: { methods: {
beginScanFiles(e, id, clinicalDataTrialSetId) { handleDragover(e) {
e.stopPropagation();
e.preventDefault();
},
handleDrop(e, id, clinicalDataTrialSetId) {
e.stopPropagation();
e.preventDefault();
this.beginScanFiles(e, id, clinicalDataTrialSetId, true)
},
async beginScanFiles(e, id, clinicalDataTrialSetId, isDrop = false) {
this.currentRow = { this.currentRow = {
Id: id, Id: id,
ClinicalDataTrialSetId: clinicalDataTrialSetId, ClinicalDataTrialSetId: clinicalDataTrialSetId,
SubjectId: this.data.SubjectId, SubjectId: this.data.SubjectId,
}; };
this.currentRow.TrialId = this.$route.query.trialId; this.currentRow.TrialId = this.$route.query.trialId;
var files = e.target.files; var files = [];
if (isDrop) {
const items = e.dataTransfer.items;
const allFiles = []; //
//
for (const item of items) {
const entry = item.webkitGetAsEntry(); //
if (entry) {
const files = await readEntry(entry); //
allFiles.push(...files);
}
}
files = allFiles
} else {
files = e.target.files
}
this.fileList = []; this.fileList = [];
for (var i = 0; i < files.length; ++i) { for (var i = 0; i < files.length; ++i) {
const fileName = files[i].name; const fileName = files[i].name;

View File

@ -142,257 +142,259 @@
</div> </div>
</div> </div>
</form> </form>
<div class="drag" ref="drag" @dragover="handleDragover" @drop="handleDrop">
<!-- 文件列表 --> <!-- 文件列表 -->
<el-table ref="dicomFilesTable" :data="uploadQueues" :row-key="(row) => row.studyIndex" class="dicomFiles-table" <el-table ref="dicomFilesTable" :data="uploadQueues" :row-key="(row) => row.studyIndex"
@selection-change="handleSelectionChange"> class="dicomFiles-table" @selection-change="handleSelectionChange">
<el-table-column type="selection" width="55" :selectable="handleSelectable" /> <el-table-column type="selection" width="55" :selectable="handleSelectable" />
<el-table-column type="index" width="40" /> <el-table-column type="index" width="40" />
<el-table-column min-width="200" show-overflow-tooltip> <el-table-column min-width="200" show-overflow-tooltip>
<template slot="header"> <template slot="header">
<el-tooltip placement="top-start"> <el-tooltip placement="top-start">
<div slot="content"> <div slot="content">
{{ $t('trials:uploadDicomList:table:studyDetail1') }}<br /> {{ $t('trials:uploadDicomList:table:studyDetail1') }}<br />
{{ $t('trials:uploadDicomList:table:studyDetail2') }}<br /> {{ $t('trials:uploadDicomList:table:studyDetail2') }}<br />
{{ $t('trials:uploadedDicoms:table:studyDate') }} {{ $t('trials:uploadedDicoms:table:studyDate') }}
</div> </div>
<span>{{ $t('trials:uploadDicomList:table:studyInfo') }}</span> <span>{{ $t('trials:uploadDicomList:table:studyInfo') }}</span>
</el-tooltip> </el-tooltip>
</template> </template>
<template slot-scope="scope"> <template slot-scope="scope">
<div style="line-height: 15px"> <div style="line-height: 15px">
<div>
<div> <div>
<span v-if="scope.row.dicomInfo.accNumber"><span style="font-weight: 500">Acc:</span> <div>
{{ scope.row.dicomInfo.accNumber }}</span> <span v-if="scope.row.dicomInfo.accNumber"><span style="font-weight: 500">Acc:</span>
<span v-else style="color: #f44336">N/A</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.modality.length > 0"> <div>
{{ scope.row.dicomInfo.modality.join('、') }},</span> <div style="display: inline-block; margin-right: 2px">
<span v-else style="color: #f44336">N/A,</span> <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>
<div style="display: inline-block; margin-right: 2px"> <div>
<span v-if="scope.row.seriesList.length">{{ scope.row.seriesList.length }} Series,</span> {{ scope.row.dicomInfo.studyTime }}
<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>
</template>
<div> </el-table-column>
<div style="display: inline-block; margin-right: 2px"> <el-table-column min-width="130" show-overflow-tooltip>
<span v-if="scope.row.dicomInfo.bodyPart"> <template slot="header">
{{ scope.row.dicomInfo.bodyPart }}, <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> </span>
<span v-else style="color: #f44336">N/A, </span>
</div> </div>
<div style="display: inline-block"> <div>
<span v-if="scope.row.dicomInfo.description"> <span :class="[
{{ scope.row.dicomInfo.description }}</span> scope.row.dicomInfo.patientSex ? '' : 'colorOfRed',
<span v-else style="color: #f44336">N/A</span> ]">
{{
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>
</div> </div>
<div> </template>
{{ scope.row.dicomInfo.studyTime }} </el-table-column>
</div> <el-table-column :label="$t('trials:uploadDicomList:table:failedFileCount')" min-width="150"
</div> show-overflow-tooltip>
</template> <!--:percentage="
</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.failedFileCount * 100) /
scope.row.dicomInfo.fileCount scope.row.dicomInfo.fileCount
" "
:show-text="false"---> :show-text="false"--->
<template slot-scope="scope"> <template slot-scope="scope">
<el-progress color="#409eff" :percentage="( <el-progress color="#409eff" :percentage="(
(scope.row.dicomInfo.uploadFileSize * 100) / (scope.row.dicomInfo.uploadFileSize * 100) /
(scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1) (scope.row.dicomInfo.fileSize ? scope.row.dicomInfo.fileSize : 1)
).toFixed(2) * 1 ).toFixed(2) * 1
" /> " />
<span> <span>
{{ $t('trials:uploadDicomList:table:uploadNow') {{ $t('trials:uploadDicomList:table:uploadNow')
}}{{ scope.row.dicomInfo.failedFileCount }}/{{ }}{{ scope.row.dicomInfo.failedFileCount }}/{{
scope.row.dicomInfo.fileCount scope.row.dicomInfo.fileCount
}} }}
({{ ({{
(scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3) (scope.row.dicomInfo.uploadFileSize / 1024 / 1024).toFixed(3)
}}MB/{{ }}MB/{{
(scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3) (scope.row.dicomInfo.fileSize / 1024 / 1024).toFixed(3)
}}MB) }}MB)
</span> </span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('trials:uploadDicomList:table:status')" min-width="140" show-overflow-tooltip> <el-table-column :label="$t('trials:uploadDicomList:table:status')" min-width="140" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<span v-if=" <span v-if="
!scope.row.dicomInfo.failedFileCount && !scope.row.dicomInfo.failedFileCount &&
!scope.row.dicomInfo.isInit !scope.row.dicomInfo.isInit
"> ">
{{ $t('trials:uploadDicomList:table:status1') }}</span> {{ $t('trials:uploadDicomList:table:status1') }}</span>
<span style="color: #409eff" v-else-if=" <span style="color: #409eff" v-else-if="
!scope.row.dicomInfo.failedFileCount && !scope.row.dicomInfo.failedFileCount &&
scope.row.dicomInfo.isInit && scope.row.dicomInfo.isInit &&
btnLoading btnLoading
">{{ $t('trials:uploadDicomList:table:status2') }}</span> ">{{ $t('trials:uploadDicomList:table:status2') }}</span>
<span style="color: #409eff" v-else-if=" <span style="color: #409eff" v-else-if="
scope.row.dicomInfo.failedFileCount < scope.row.dicomInfo.failedFileCount <
scope.row.dicomInfo.fileCount && scope.row.dicomInfo.fileCount &&
!scope.row.uploadState.record !scope.row.uploadState.record
">{{ $t('trials:uploadDicomList:table:status2') }}</span> ">{{ $t('trials:uploadDicomList:table:status2') }}</span>
<span style="color: #2cc368" v-else-if=" <span style="color: #2cc368" v-else-if="
scope.row.dicomInfo.failedFileCount === scope.row.dicomInfo.failedFileCount ===
scope.row.dicomInfo.fileCount scope.row.dicomInfo.fileCount
">{{ $t('trials:uploadDicomList:table:status3') }}</span> ">{{ $t('trials:uploadDicomList:table:status3') }}</span>
<span style="color: #f66" v-else-if=" <span style="color: #f66" v-else-if="
scope.row.uploadState.record && scope.row.uploadState.record &&
scope.row.uploadState.record.fileCount === 0 scope.row.uploadState.record.fileCount === 0
">{{ $t('trials:uploadDicomList:table:status5') }}</span> ">{{ $t('trials:uploadDicomList:table:status5') }}</span>
<span style="color: #f66" v-else>{{ <span style="color: #f66" v-else>{{
$t('trials:uploadDicomList:table:Failed') $t('trials:uploadDicomList:table:Failed')
}}</span> }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip> <el-table-column :label="$t('trials:uploadDicomList:table:record')" min-width="140" show-overflow-tooltip>
<template slot-scope="scope"> <template slot-scope="scope">
<el-tooltip placement="top" v-if="scope.row.uploadState.record"> <el-tooltip placement="top" v-if="scope.row.uploadState.record">
<div slot="content"> <div slot="content">
<div style="max-height: 500px; overflow-y: auto"> <div style="max-height: 500px; overflow-y: auto">
{{ $t('trials:uploadDicomList:table:Existed') }}: {{ $t('trials:uploadDicomList:table:Existed') }}:
<div v-if="scope.row.uploadState.record.Existed.length"> <div v-if="scope.row.uploadState.record.Existed.length">
<div v-for="item of scope.row.uploadState.record.Existed" :key="item" <div v-for="item of scope.row.uploadState.record.Existed" :key="item"
style="font-size: 12px; color: #baa72a"> style="font-size: 12px; color: #baa72a">
{{ item }} {{ item }}
</div>
</div> </div>
</div> <div v-else>&nbsp;</div>
<div v-else>&nbsp;</div> {{ $t('trials:uploadDicomList:table:Uploaded') }}:
{{ $t('trials:uploadDicomList:table:Uploaded') }}: <div v-if="scope.row.uploadState.record.Uploaded.length">
<div v-if="scope.row.uploadState.record.Uploaded.length"> <div v-for="item of scope.row.uploadState.record.Uploaded" :key="item"
<div v-for="item of scope.row.uploadState.record.Uploaded" :key="item" style="font-size: 12px; color: #24b837">
style="font-size: 12px; color: #24b837"> {{ item }}
{{ item }} </div>
</div> </div>
</div> <div v-else>&nbsp;</div>
<div v-else>&nbsp;</div> <br />
<br /> {{ $t('trials:uploadDicomList:table:Failed') }}:
{{ $t('trials:uploadDicomList:table:Failed') }}: <div v-if="scope.row.uploadState.record.Failed.length">
<div v-if="scope.row.uploadState.record.Failed.length"> <div v-for="item of scope.row.uploadState.record.Failed" :key="item"
<div v-for="item of scope.row.uploadState.record.Failed" :key="item" style="font-size: 12px; color: #f66">
style="font-size: 12px; color: #f66"> {{ item }}
{{ item }} </div>
</div> </div>
<div v-else>&nbsp;</div>
</div> </div>
<div v-else>&nbsp;</div>
</div> </div>
</div> <el-button size="mini" style="cursor: pointer">
<el-button size="mini" style="cursor: pointer"> <span style="font-size: 12px; color: #baa72a">{{
<span style="font-size: 12px; color: #baa72a">{{ scope.row.uploadState.record.Existed.length
scope.row.uploadState.record.Existed.length }}</span>
}}</span> /
/ <span style="font-size: 12px; color: #24b837">{{
<span style="font-size: 12px; color: #24b837">{{ scope.row.uploadState.record.Uploaded.length
scope.row.uploadState.record.Uploaded.length }}</span>
}}</span> /
/ <span style="font-size: 12px; color: #f66">{{
<span style="font-size: 12px; color: #f66">{{ scope.row.uploadState.record.Failed.length
scope.row.uploadState.record.Failed.length }}</span>
}}</span> </el-button>
</el-button> </el-tooltip>
</el-tooltip> </template>
</template> </el-table-column>
</el-table-column> <el-table-column v-show="isScan" :label="$t('common:action:action')" width="200">
<el-table-column v-show="isScan" :label="$t('common:action:action')" width="200"> <template slot-scope="scope">
<template slot-scope="scope"> <!-- 预览 -->
<!-- 预览 --> <!-- :disabled="scope.row.dicomInfo.failedFileCount < scope.row.dicomInfo.fileCount && scope.row.dicomInfo.failedFileCount !== 0"-->
<!-- :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 !== '' &&
<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.failedFileCount <
scope.row.dicomInfo.fileCount && scope.row.dicomInfo.fileCount &&
!scope.row.uploadState.record) || !scope.row.uploadState.record) ||
btnLoading btnLoading
" @click="handleDelete(scope.$index, scope.row)" /> " :title="$t('trials:uploadedDicoms:action:preview')" size="small"
</template> @click="handlePreview(scope.row.dicomInfo.studyUid)" />
</el-table-column> <!-- 移除 -->
</el-table> <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>
<div style="text-align: right; padding: 10px 0px"> <div style="text-align: right; padding: 10px 0px">
<!-- 关闭 --> <!-- 关闭 -->
<!-- <el-button :disabled="btnLoading" size="small" type="primary" @click="cancel"> <!-- <el-button :disabled="btnLoading" size="small" type="primary" @click="cancel">
@ -567,6 +569,7 @@ import DicomPreview from '@/views/dicom-show/dicom-preview'
import uploadPetClinicalData from './uploadPetClinicalData.vue' import uploadPetClinicalData from './uploadPetClinicalData.vue'
import dicomStore from '@/utils/dicom-store' import dicomStore from '@/utils/dicom-store'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { readEntry } from '@/utils/index'
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload' import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
import { convertBytes } from '@/utils/dicom-character-set' import { convertBytes } from '@/utils/dicom-character-set'
import moment from 'moment' import moment from 'moment'
@ -676,6 +679,15 @@ export default {
this.OSSclient.close() this.OSSclient.close()
}, },
methods: { methods: {
handleDragover(e) {
e.stopPropagation();
e.preventDefault();
},
handleDrop(e) {
e.stopPropagation();
e.preventDefault();
this.beginScanFiles(e, true)
},
getParentList() { getParentList() {
this.getStudyInfo() this.getStudyInfo()
this.$emit('getList') this.$emit('getList')
@ -802,8 +814,24 @@ export default {
window.open(routeData.href, '_blank') window.open(routeData.href, '_blank')
}, },
// //
beginScanFiles(e) { async beginScanFiles(e, isDrop = false) {
var files = e.target.files var files = []
if (isDrop) {
const items = e.dataTransfer.items;
const allFiles = []; //
//
for (const item of items) {
const entry = item.webkitGetAsEntry(); //
if (entry) {
const files = await readEntry(entry); //
allFiles.push(...files);
}
}
files = allFiles
} else {
files = e.target.files
}
if (files.length > 0) { if (files.length > 0) {
var checkFiles = [...files] var checkFiles = [...files]
let max = checkFiles.some((item) => item.size > 20 * 1024 * 1024 * 1024) let max = checkFiles.some((item) => item.size > 20 * 1024 * 1024 * 1024)
@ -1098,6 +1126,7 @@ export default {
} }
} }
reader.onerror = function (e) { reader.onerror = function (e) {
console.log(e, 'err')
resolve() resolve()
} }
reader.readAsArrayBuffer(file) reader.readAsArrayBuffer(file)

View File

@ -230,50 +230,52 @@
</div> </div>
</div> </div>
</form> </form>
<!-- 文件列表 --> <div class="drag" ref="drag" @dragover="handleDragover" @drop="handleDrop">
<el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300" <!-- 文件列表 -->
@selection-change="handleSelectionChange"> <el-table ref="filesTable" :data="fileList" class="dicomFiles-table" height="300"
<el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !btnLoading" /> @selection-change="handleSelectionChange">
<el-table-column type="index" width="50" /> <el-table-column type="selection" width="55" :selectable="(row, index) => row.status !== 2 && !btnLoading" />
<!-- 文件名称 --> <el-table-column type="index" width="50" />
<el-table-column prop="name" :label="$t('trials:uploadNonDicoms:table:fileName')" min-width="100" /> <!-- 文件名称 -->
<!-- 文件大小 --> <el-table-column prop="name" :label="$t('trials:uploadNonDicoms:table:fileName')" min-width="100" />
<el-table-column prop="size" :label="$t('trials:uploadNonDicoms:table:fileSize')"> <!-- 文件大小 -->
<template slot-scope="scope"> <el-table-column prop="size" :label="$t('trials:uploadNonDicoms:table:fileSize')">
<span>{{ <template slot-scope="scope">
scope.row.size && scope.row.size > 0 <span>{{
? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB` scope.row.size && scope.row.size > 0
: '0MB' ? `${(scope.row.size / 1024 / 1024).toFixed(3)}MB`
}}</span> : '0MB'
</template> }}</span>
</el-table-column> </template>
<!-- 文件类型 --> </el-table-column>
<el-table-column prop="type" :label="$t('trials:uploadNonDicoms:table:fileType')" /> <!-- 文件类型 -->
<!-- 上传状态 --> <el-table-column prop="type" :label="$t('trials:uploadNonDicoms:table:fileType')" />
<el-table-column prop="status" :label="$t('trials:uploadNonDicoms:table:uploadStatus')" min-width="100"> <!-- 上传状态 -->
<template slot-scope="scope"> <el-table-column prop="status" :label="$t('trials:uploadNonDicoms:table:uploadStatus')" min-width="100">
<el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]" <template slot-scope="scope">
v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }} <el-tag :type="['warning', 'info', 'success', 'danger'][scope.row.status]"
</el-tag> v-if="scope.row.status || scope.row.status === 0">{{ $fd('NoneDicomUploadStatus', scope.row.status) }}
</template> </el-tag>
</el-table-column> </template>
<el-table-column :label="$t('trials:uploadNonDicoms:table:failedFileCount')" min-width="150" </el-table-column>
show-overflow-tooltip> <el-table-column :label="$t('trials:uploadNonDicoms:table:failedFileCount')" min-width="150"
<template slot-scope="scope"> show-overflow-tooltip>
<el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) * <template slot-scope="scope">
1 <el-progress color="#409eff" :percentage="scope.row.size && scope.row.size > 0 ? ((scope.row.uploadFileSize * 100) / scope.row.size).toFixed(2) *
: ((scope.row.uploadFileSize * 100) / 1).toFixed(2) * 1
1 : ((scope.row.uploadFileSize * 100) / 1).toFixed(2) *
" /> 1
</template> " />
</el-table-column> </template>
<el-table-column :label="$t('common:action:action')"> </el-table-column>
<template slot-scope="scope"> <el-table-column :label="$t('common:action:action')">
<el-button size="mini" icon="el-icon-delete" circle :disabled="btnLoading" <template slot-scope="scope">
:title="$t('trials:crcUpload:action:delete')" @click="handleRemoveFile(scope.row)" /> <el-button size="mini" icon="el-icon-delete" circle :disabled="btnLoading"
</template> :title="$t('trials:crcUpload:action:delete')" @click="handleRemoveFile(scope.row)" />
</el-table-column> </template>
</el-table> </el-table-column>
</el-table>
</div>
<div style="text-align: right; padding: 10px 0px"> <div style="text-align: right; padding: 10px 0px">
<span style="margin-right: 10px">{{ <span style="margin-right: 10px">{{
$store.state.trials.uploadTip $store.state.trials.uploadTip
@ -334,6 +336,7 @@ import {
deleteNoneDicomStudyFile, deleteNoneDicomStudyFile,
} from '@/api/trials' } from '@/api/trials'
import { getToken } from '@/utils/auth' import { getToken } from '@/utils/auth'
import { readEntry } from '@/utils/index'
// import PreviewFiles from './previewFiles' // import PreviewFiles from './previewFiles'
// import uploadVideos from '@/components/videos' // import uploadVideos from '@/components/videos'
import moment from 'moment' import moment from 'moment'
@ -454,6 +457,15 @@ export default {
}, },
}, },
methods: { methods: {
handleDragover(e) {
e.stopPropagation();
e.preventDefault();
},
handleDrop(e) {
e.stopPropagation();
e.preventDefault();
this.beginScanFiles(e, true)
},
// Dicom // Dicom
getNoneDicomList() { getNoneDicomList() {
this.loading = true this.loading = true
@ -634,8 +646,24 @@ export default {
} }
}, },
// //
beginScanFiles(e) { async beginScanFiles(e, isDrop = false) {
var files = [...e.target.files] var files = []
if (isDrop) {
const items = e.dataTransfer.items;
const allFiles = []; //
//
for (const item of items) {
const entry = item.webkitGetAsEntry(); //
if (entry) {
const files = await readEntry(entry); //
allFiles.push(...files);
}
}
files = allFiles
} else {
files = [...e.target.files]
}
var sameFiles = [] var sameFiles = []
files.forEach((file) => { files.forEach((file) => {
var extendName = file.name var extendName = file.name