irc_web/src/views/trials/trials-panel/trial-summary/image-summary/index.vue

409 lines
20 KiB
Vue

<template>
<BaseContainer class="image-summary-wrapper">
<template slot="search-container">
<el-form :inline="true">
<!-- 中心 -->
<el-form-item :label="$t('trials:imageSummary:table:siteNo')">
<el-select v-model="searchData.TrialSiteId" clearable filterable>
<el-option v-for="(item, index) of siteOptions" :key="index" :label="item.TrialSiteCode"
:value="item.TrialSiteId" />
</el-select>
</el-form-item>
<!-- 受试者 -->
<el-form-item :label="$t('trials:imageSummary:table:subject')">
<el-input v-model="searchData.SubjectCode" />
</el-form-item>
<!-- 拍片时间 -->
<el-form-item :label="$t('trials:imageSummary:table:operateTime')">
<el-date-picker v-model="timeList" @change="changeTimeList" value-format="yyyy-MM-dd HH:mm:ss"
:default-time="['00:00:00', '23:59:59']" type="datetimerange">
</el-date-picker>
</el-form-item>
<el-form-item>
<el-button type="primary" icon="el-icon-search" @click="handleSearch">
{{ $t('common:button:search') }}
</el-button>
<el-button type="primary" icon="el-icon-refresh-left" @click="handleReset">
{{ $t('common:button:reset') }}
</el-button>
<el-button type="primary" @click="handleExport">
{{ $t('common:button:export') }}
</el-button>
<el-button type="primary" @click="handleExportImage(false)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_dicom') }}
</el-button>
<el-button type="primary" @click="handleExportImage(false, true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportImage'])">
{{ $t('trials:imageSummary:button:export_readingDicom') }}
</el-button>
<el-button type="primary" @click="handleExportImage(true)" :disabled="selectArr.length <= 0"
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:exportKeyImage'])">
{{ $t('trials:imageSummary:button:export_image') }}
</el-button>
<el-button type="primary" @click="statistics">
{{ $t('trials:imageSummary:button:statistics') }}
</el-button>
</el-form-item>
</el-form>
</template>
<template slot="main-container">
<el-table v-adaptive="{ bottomOffset: 60 }" v-loading="loading" :data="list" @sort-change="handleSortChange"
@selection-change="handleSelectionChange" stripe height="100"
:default-sort="{ prop: 'CreateTime', order: 'descending' }">
<el-table-column type="selection" width="55" />
<!-- 中心编号 -->
<el-table-column prop="TrialSiteCode" min-width="100" :label="$t('trials:imageSummary:table:siteNo')"
show-overflow-tooltip sortable="custom" />
<!-- 受试者 -->
<el-table-column prop="SubjectCode" min-width="100" :label="$t('trials:imageSummary:table:subject')"
show-overflow-tooltip sortable="custom" />
<!-- 访视 -->
<el-table-column prop="VisitName" min-width="120" :label="$t('trials:imageSummary:table:visit')"
show-overflow-tooltip sortable="custom" />
<!-- 检查数量 -->
<el-table-column prop="TotalStudyCount" min-width="120"
:label="$t('trials:imageSummary:table:TotalStudyCount')" show-overflow-tooltip sortable="custom" />
<!-- 影像类型 -->
<el-table-column prop="VisitName" min-width="120" :label="$t('trials:imageSummary:table:imageType')"
show-overflow-tooltip sortable="custom">
<template slot-scope="scope">
<el-tag v-if="scope.row.IsHaveDicom" type="primary">{{
$fd('IsDicom', true)
}}</el-tag>
<el-tag v-if="scope.row.IsHaveNoneDicom" type="primary">{{
$fd('IsDicom', false)
}}</el-tag>
</template>
</el-table-column>
<!-- 影像数量 -->
<el-table-column prop="TotalImageCount" min-width="120"
:label="$t('trials:imageSummary:table:TotalImageCount')" show-overflow-tooltip sortable="custom" />
<!-- 影像大小 -->
<el-table-column prop="TotalImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalImageSizeStr')" show-overflow-tooltip
sortable="custom" />
<!-- 阅片影像大小 -->
<el-table-column prop="TotalReadingImageSizeStr" min-width="120"
:label="$t('trials:imageSummary:table:TotalReadingImageSizeStr')" show-overflow-tooltip
sortable="custom" />
<!-- 最早拍片日期 -->
<el-table-column prop="EarliestScanDate" min-width="120"
:label="$t('trials:imageSummary:table:EarliestScanDate')" show-overflow-tooltip sortable="custom" />
<!-- 最晚拍片日期 -->
<el-table-column prop="LatestScanDate" min-width="120"
:label="$t('trials:imageSummary:table:LatestScanDate')" show-overflow-tooltip sortable="custom" />
<el-table-column prop="" fixed="right" :label="$t('common:action:action')" show-overflow-tooltip
v-if="hasPermi(['trials:trials-panel:trial-summary:image-summary:toUpload', 'trials:tab:uploadMonitor'])">
<template slot-scope="scope">
<!-- 详情 -->
<el-button icon="el-icon-position" circle @click="toUpload(scope.row)"
:title="$t('trials:imageSummary:action:toUpload')" />
</template>
</el-table-column>
</el-table>
<pagination class="page" :total="total" :page.sync="searchData.PageIndex" :limit.sync="searchData.PageSize"
@pagination="getList" />
<div class="remark">
<span>{{ $t('trials:imageSummary:remark:TotalImageSizeStr') }}</span>
<span class="size">{{ image_size.TotalImageSizeStr }}</span>,
<span>{{ $t('trials:imageSummary:remark:SubjectImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectImageAVGSizeStr }} </span>,
<span>{{ $t('trials:imageSummary:remark:SubjectVisitImageAVGSizeStr') }}</span>
<span class="size">{{ image_size.SubjectVisitImageAVGSizeStr }}</span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:TotalReadingImageSizeStr') }}</span>
<span class="size">{{ image_size.TotalReadingImageSizeStr }} </span><span>{{ `; ` }}</span>
<span>{{ $t('trials:imageSummary:remark:CheckImageSize') }}</span>
<span class="size">{{ image_size.CheckImageSize }} </span>
</div>
</template>
</BaseContainer>
</template>
<script>
import Pagination from '@/components/Pagination'
import BaseContainer from '@/components/BaseContainer'
import { getTrialSiteSelect, getTrialVisitImageStatList, getTrialVisitImageStatInfo, getExportSubjectVisitImageList } from '@/api/trials'
import { downLoadFile } from '@/utils/stream.js'
import { getTrialVisitImageStatList_Export } from '@/api/export'
const searchDataDefault = () => {
return {
SortField: '',
Asc: false,
PageIndex: 1,
PageSize: 20,
TrialSiteId: null,
SubjectCode: null,
BeginScanDate: null,
EndScanDate: null
}
}
export default {
name: "imageSummary",
components: { Pagination, BaseContainer },
data() {
return {
total: 0,
loading: false,
searchData: searchDataDefault(),
ResearchProgramNo: null,
list: [],
siteOptions: [],
timeList: [],
selectArr: [],
image_size: {
TotalImageSizeStr: null,
SubjectImageAVGSizeStr: null,
SubjectVisitImageAVGSizeStr: null,
TotalReadingImageSizeStr: null,
CheckImageSize: null
}
}
},
created() {
this.getSite()
this.getList()
},
methods: {
async getList() {
try {
this.searchData.TrialId = this.$route.query.trialId
this.loading = true
let res = await getTrialVisitImageStatList(this.searchData)
this.loading = false
if (res.IsSuccess) {
this.list = res.Result.CurrentPageData
this.total = res.Result.TotalCount
}
} catch (err) {
this.loading = false
console.log(err)
}
},
// 导出表格
async handleExport() {
this.loading = true
try {
await getTrialVisitImageStatList_Export(this.searchData)
this.loading = false
} catch (e) {
this.loading = false
}
},
// 导出影像或关键图
async handleExportImage(IsKeyImage = false, IsExportReading = false) {
try {
let data = {
TrialId: this.$route.query.trialId,
IsKeyImage,
IsExportReading
}
data.SubjectVisitIdList = this.selectArr.map(item => item.SubjectVisitId)
if (!IsKeyImage) {
let confirm = await this.$confirm(this.$t('trials:imageSummary:confirm:space').replace('xxx', this.image_size.CheckImageSize))
if (!confirm) return false
}
let res = await getExportSubjectVisitImageList(data)
if (res.IsSuccess) {
this.downLoad(IsKeyImage, res.Result, IsExportReading)
}
} catch (err) {
console.log(err)
}
},
// 下载
async downLoad(IsKeyImage = false, row, IsExportReading = false) {
try {
let { files, name } = this.formatDownloadFile(IsKeyImage, row, IsExportReading)
let res = await downLoadFile(files, name, 'zip')
// }
} catch (err) {
console.log(err)
}
},
// 格式化下载文件路径
formatDownloadFile(IsKeyImage = false, row, IsExportReading = false) {
let files = [],
name = `${this.$route.query.researchProgramNo}_${this.$t('trials:imageSummary:downloadname:dicom')}_${Date.now()}.zip`;
if (IsExportReading) {
name = `${this.$route.query.researchProgramNo}_${this.$t('trials:imageSummary:downloadname:readingDicom')}_${Date.now()}.zip`;
}
if (!IsKeyImage) {
//中心ID/受试者ID/访视名/Study ID_Study Date_Modality/文件
row.VisitList.forEach(visit => {
if (visit.StudyList && visit.StudyList.length > 0) {
visit.StudyList.forEach(study => {
let arr = []
study.SeriesList.forEach(item => {
if (!arr.includes(item.Modality)) {
arr.push(item.Modality)
}
})
let str = arr.join('_')
let time = study.StudyTime.split(' ')[0]
if (study.StudyDIRPath && !study.dirHas) {
study.dirHas = true
let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${time}_${str}/DICOMDIR`,
url: this.OSSclientConfig.basePath + study.StudyDIRPath,
}
files.push(obj)
}
if (study.SeriesList && study.SeriesList.length > 0) {
study.SeriesList.forEach(serie => {
if (serie.InstanceList && serie.InstanceList.length > 0) {
serie.InstanceList.forEach(instance => {
let instanceArr = instance.Path.split("/")
let fileName = instance.FileName || instanceArr[instanceArr.length - 1]
let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${study.StudyCode}_${time}_${str}/IMAGE/${fileName}`,
url: this.OSSclientConfig.basePath + instance.Path,
IsEncapsulated: instance.IsEncapsulated
}
files.push(obj)
})
}
})
}
})
}
if (visit.NoneDicomStudyList && visit.NoneDicomStudyList.length > 0) {
visit.NoneDicomStudyList.forEach(noneDicomStudy => {
if (noneDicomStudy.FileList && noneDicomStudy.FileList.length > 0) {
noneDicomStudy.FileList.forEach(file => {
let time = noneDicomStudy.ImageDate.split(' ')[0]
let obj = {
name: `${visit.TrialSiteCode}/${visit.SubjectCode}/${visit.VisitName}/${noneDicomStudy.StudyCode}_${time}_${noneDicomStudy.Modality}/${file.FileName}`,
url: this.OSSclientConfig.basePath + file.Path,
}
files.push(obj)
})
}
})
}
})
} else {
//项目研究方案号(评估标准)/中心ID/受试者ID/访视名/阅片人角色-裁判选择标记/文件名
name = `${this.$route.query.researchProgramNo}_${this.$t('trials:imageSummary:downloadname:keyImage')}_${Date.now()}.zip`
row.forEach(item => {
['QuestionMarkPictureList', 'TableQuestionRowPictureList', 'ReadingNoneDicomMarkPathList'].forEach(key => {
if (item[key] && item[key].length > 0) {
item[key].forEach(data => {
['PicturePath', 'otherPicturePath'].forEach(imgKey => {
if (data[imgKey]) {
let arr = data[imgKey].split("/")
let fileName = arr[arr.length - 1]
let obj = {
name: `${item.CriterionName}/${item.TrialSiteCode}/${item.SubjectCode}/${item.VisitName}/${this.$fd('ArmEnum', item.ArmEnum)}_${this.$fd('IsJudgeSelect', String(item.IsJudgeSelect))}/${fileName}`,
url: this.OSSclientConfig.basePath + data[imgKey],
}
files.push(obj)
}
})
})
}
})
})
}
return { files, name }
},
// 获取统计数据
async statistics() {
try {
let params = {
TrialId: this.$route.query.trialId
}
this.loading = true
let res = await getTrialVisitImageStatInfo(params)
this.loading = false
if (res.IsSuccess) {
this.image_size.TotalImageSizeStr = res.Result.TotalImageSizeStr;
this.image_size.SubjectImageAVGSizeStr = res.Result.SubjectImageAVGSizeStr;
this.image_size.SubjectVisitImageAVGSizeStr = res.Result.SubjectVisitImageAVGSizeStr;
this.image_size.TotalReadingImageSizeStr = res.Result.TotalReadingImageSizeStr;
}
} catch (err) {
this.loading = false
console.log(err)
}
},
// 跳转至上传记录页
toUpload(row) {
let query = this.$route.query
query.siteId = row.TrialSiteId
query.subjectCode = row.SubjectCode
query.visitNum = row.VisitNum
this.$router.push({
path: '/trials/trials-panel/trial-summary/upload-monitor',
query
})
},
handleSelectionChange(selection) {
this.selectArr = selection
let num = this.selectArr.reduce((sum, item) => sum + item.TotalImageSize, 0)
if (num <= 0) return this.image_size.CheckImageSize = `0MB`
this.image_size.CheckImageSize = this.$FormatSize(num)
},
// 获取site下拉框数据
getSite() {
getTrialSiteSelect(this.$route.query.trialId).then(res => {
this.siteOptions = res.Result
})
},
changeTimeList() {
if (this.timeList) {
this.searchData.BeginScanDate = this.timeList[0]
this.searchData.EndScanDate = this.timeList[1]
} else {
this.searchData.BeginScanDate = null
this.searchData.EndScanDate = null
}
},
handleReset() {
this.searchData = searchDataDefault()
this.timeList = []
this.getList()
},
handleSearch() {
this.searchData.PageIndex = 1
this.getList()
},
handleSortChange(column) {
if (column.order === 'ascending') {
this.searchData.Asc = true
} else {
this.searchData.Asc = false
}
let prop = column.prop
if (prop === 'TotalImageSizeStr') {
prop = 'TotalImageSize'
}
if (prop === 'TotalReadingImageSizeStr') {
prop = 'TotalReadingImageSize'
}
this.searchData.SortField = prop
this.searchData.PageIndex = 1
this.getList()
},
}
}
</script>
<style lang="scss" scoped>
.image-summary-wrapper {
position: relative;
.remark {
position: absolute;
left: 5px;
bottom: 7px;
font-size: 12px;
.size {
display: inline-block;
min-width: 50px;
}
}
}
</style>