Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ecaf5e267 | |||
| 1ca4fb7dd4 | |||
| cb2fed1ad2 | |||
| 4c642cd814 | |||
| 9dcbad7616 | |||
| 197b3213e7 | |||
| 3bfda749d8 | |||
| 6f911d0d74 | |||
| 78f4a78994 | |||
| 4e1911223d | |||
| 7dd02e84aa | |||
| 7f260799d8 | |||
| 06c7a8126b | |||
| 78624d9cce | |||
| 6ecc0e58e9 | |||
| 84a81e1851 | |||
| b09209af31 | |||
| 9892070ccc | |||
| 63cbc8746f | |||
| fe64feac80 | |||
| dce7fd9737 | |||
| 6187c585ad | |||
| 22ac496d7b | |||
| 45c0e5030b | |||
| 36e23b8135 | |||
| b530f68446 | |||
| 383bfabae8 | |||
| 196ed7f993 | |||
| 70cc0027cd | |||
| 975b7d39a7 | |||
| 21bcd1fddb | |||
| 04bbde8583 | |||
| f3c4bedbfd | |||
| 835aedc800 | |||
| 9026b1d7fd | |||
| b8f96efa66 | |||
| 4c4f68dbd0 | |||
| 11c56d2f7a | |||
| a72521304e | |||
| 8baf6cb88f | |||
| 71e04c3bf1 | |||
| 1af9b48622 | |||
| 447b74fa55 | |||
| c633fbcf87 | |||
| 1cc57ad1d6 | |||
| f282fdfabc | |||
| d77c6ecf03 | |||
| 1db75cf4f7 | |||
| 7bc70bfd6c | |||
| 69ba30e5a9 | |||
| 18482ddaa9 | |||
| 14e2afcfee | |||
| 39dadbbf47 | |||
| d0ba340fea |
+2
-1
@@ -98,6 +98,7 @@ import timeTag from '@/components/timeTag'
|
||||
import Vue from 'vue'
|
||||
import i18n from './lang'
|
||||
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
|
||||
import WHITELIST from "./utils/whiteList"
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
@@ -156,7 +157,7 @@ export default {
|
||||
// },
|
||||
methods: {
|
||||
getIsLock() {
|
||||
if (zzSessionStorage.getItem('isLock') === 'true') {
|
||||
if (zzSessionStorage.getItem('isLock') === 'true' && !WHITELIST.includes(this.$route.path)) {
|
||||
this.isLock = true
|
||||
} else {
|
||||
this.isLock = false
|
||||
|
||||
@@ -480,3 +480,32 @@ export function getNoneDicomMarkList(data) {
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function getFilterTableQuestion(data) {
|
||||
return request({
|
||||
url: `/ReadingImageTask/getFilterTableQuestion`,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function deleteImageCache(params) {
|
||||
return request({
|
||||
url: `/Study/deleteImageCache`,
|
||||
method: 'delete',
|
||||
params
|
||||
})
|
||||
}
|
||||
export function getAnonymizeInfo(params) {
|
||||
return request({
|
||||
url: `/Study/getAnonymizeInfo`,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
export function updateModality(params) {
|
||||
return request({
|
||||
url: `/Study/updateModality`,
|
||||
method: 'put',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
+21
-1
@@ -4522,4 +4522,24 @@ export function addOrUpdateCommonUploadRecord(data) {
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export function getInspectionById(data) {
|
||||
return request({
|
||||
url: `/Inspection/getInspectionById`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
export function setJsonDetail(data) {
|
||||
return request({
|
||||
url: `/Inspection/setJsonDetail`,
|
||||
method: 'post',
|
||||
data,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
</div>
|
||||
|
||||
<div class="info-subject">
|
||||
<div v-if="series.subjectCode">{{ series.subjectCode }}</div>
|
||||
<div v-if="series.visitName">{{ series.visitName }}</div>
|
||||
<div v-if="series.subjectCode && IsReadingTaskViewInOrder !== 0">{{ series.subjectCode }}</div>
|
||||
<div v-if="series.visitName && IsReadingTaskViewInOrder !== 0">{{ series.visitName }}</div>
|
||||
<div>{{ stack.description }}</div>
|
||||
<!-- <div>{{ dicomInfo.hospital }}</div> -->
|
||||
<!-- <div v-show="dicomInfo.pid">{{ dicomInfo.pid }}</div> -->
|
||||
@@ -174,7 +174,8 @@ export default {
|
||||
orientationMarkers: [],
|
||||
originalMarkers: [],
|
||||
dcmTag: { visible: false, title: this.$t('trials:dicom-tag:title') },
|
||||
tip: ''
|
||||
tip: '',
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
|
||||
@@ -182,6 +183,9 @@ export default {
|
||||
this.type = this.$router.currentRoute.query.type
|
||||
? this.$router.currentRoute.query.type
|
||||
: ''
|
||||
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
|
||||
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
|
||||
}
|
||||
this.canvas = this.$refs.canvas
|
||||
this.canvas.addEventListener('cornerstonenewimage', this.onNewImage)
|
||||
this.canvas.addEventListener(
|
||||
@@ -209,6 +213,10 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
getInfo() {
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
return image
|
||||
},
|
||||
loadImageStack(dicomSeries, text = '') {
|
||||
this.tip = text
|
||||
this.$nextTick(() => {
|
||||
|
||||
@@ -296,6 +296,13 @@
|
||||
<option v-for="(item, index) in colormapsList" :key="index" :value="item.id">{{ item.name }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="sideTool-wrapper">
|
||||
<label for="Replacement" style="display: inline-block;color: #fff;line-height: 20px;cursor: pointer;">
|
||||
替换
|
||||
</label>
|
||||
<input type="file" id="Replacement" @change="beginScanFiles($event, 'replace')" style="display: none;">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 患者信息 -->
|
||||
@@ -382,6 +389,7 @@ import {
|
||||
editPatientInfo
|
||||
} from '@/api/trials'
|
||||
import { setPTClinicalDataForInstance, clearPTClinicalDataCache } from '@/utils/ptClinicalDataCache'
|
||||
import { changeFile } from "@/views/trials/trials-panel/reading/dicoms/components/upload.js"
|
||||
export default {
|
||||
name: 'DicomsViewer',
|
||||
components: {
|
||||
@@ -400,6 +408,14 @@ export default {
|
||||
modality: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
SeriesList: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
currentSeriesIndex: {
|
||||
type: Number,
|
||||
default: -1
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -483,7 +499,9 @@ export default {
|
||||
},
|
||||
formLoading: false,
|
||||
type: '',
|
||||
isEdit: 0
|
||||
isEdit: 0,
|
||||
fileKey: null,
|
||||
file: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -511,6 +529,19 @@ export default {
|
||||
},
|
||||
|
||||
methods: {
|
||||
beginScanFiles(e, key) {
|
||||
this.fileKey = key
|
||||
this.file = e.target.files[0]
|
||||
let image = this.$refs[this.activeItem].getInfo()
|
||||
let study = {
|
||||
seriesList: this.SeriesList,
|
||||
currentSeriesIndex: this.currentSeriesIndex
|
||||
}
|
||||
this.$emit("update:loading", true)
|
||||
changeFile('CRC', this.file, study, image)
|
||||
|
||||
// DicomEvent.$emit('getStudyFile')
|
||||
},
|
||||
setToolsPassive() {
|
||||
const elements = document.querySelectorAll('.dicom-item')
|
||||
const scope = this
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
<el-table-column type="index" width="40" />
|
||||
<!--受试者-->
|
||||
<el-table-column :label="$t('download:table:subjectCode')" min-width="130" prop="SubjectCode"
|
||||
show-overflow-tooltip />
|
||||
show-overflow-tooltip v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" sortable v-if="IsImageSegment" />
|
||||
<!--任务名称-->
|
||||
@@ -78,7 +78,7 @@
|
||||
</el-table>
|
||||
<study-view v-if="model_cfg.visible" :model_cfg="model_cfg" :modelList="modelList" :bodyPart="bodyPart"
|
||||
:subjectVisitId="modelSubjectVisitId" :IsDicom="IsDicom" :isDownload="true" :visitTaskId="modelTaskId"
|
||||
:IsImageSegment="IsImageSegment" :Criterion="Criterion" />
|
||||
:IsImageSegment="IsImageSegment" :Criterion="Criterion" :IsReadingTaskViewInOrder="isReadingTaskViewInOrder" />
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script>
|
||||
@@ -136,6 +136,14 @@ export default {
|
||||
IsImageSegment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
default: 2,
|
||||
},
|
||||
isReading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -170,6 +178,7 @@ export default {
|
||||
this.getList()
|
||||
this.title = `Download Images:${this.SubjectCode}(${this.Criterion.TrialReadingCriterionName})`
|
||||
if (this.IsImageSegment) this.title = `Download Images:${this.SubjectCode}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.title = ''
|
||||
},
|
||||
beforeDestroy() {
|
||||
store.dispatch('trials/setUnLock', false)
|
||||
@@ -437,6 +446,9 @@ export default {
|
||||
let params = {
|
||||
TrialImageDownloadId: this.downloadId,
|
||||
}
|
||||
if (this.isReading) {
|
||||
params.VisitTaskId = this.TaskId
|
||||
}
|
||||
await downloadImageSuccess(params)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
@@ -447,6 +459,9 @@ export default {
|
||||
if (this.IsImageSegment) {
|
||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${item.VisitName}`
|
||||
}
|
||||
if (this.isReadingTaskViewInOrder === 0) {
|
||||
this.model_cfg.title = ''
|
||||
}
|
||||
if (item.IsDicom) {
|
||||
this.modelList = item.DicomStudyList
|
||||
} else {
|
||||
@@ -488,11 +503,11 @@ export default {
|
||||
let routeData = null
|
||||
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
} else {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
}
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
@@ -505,7 +520,7 @@ export default {
|
||||
var token = getToken()
|
||||
let trialId = this.$route.query.trialId
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}`,
|
||||
path: `/showvisitdicoms?page=download&trialId=${trialId}&visitTaskId=${row.VisitTaskId}&subjectVisitId=${row.SourceSubjectVisitId}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
<!--检查列表-->
|
||||
<el-table :data="list" style="width: 100%" height="300" :loading="loading">
|
||||
<!--受试者-->
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable />
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:dicom:table:subjectCode')" sortable
|
||||
v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('download:table:VisitName')" v-if="IsImageSegment" sortable />
|
||||
<!--任务名称-->
|
||||
@@ -42,7 +43,8 @@
|
||||
<template slot-scope="scope">
|
||||
<div class="btnBox">
|
||||
<!--上传--->
|
||||
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data" v-if="!forbid">
|
||||
<form id="inputForm" :ref="`uploadForm_${scope.row.Id}`" enctype="multipart/form-data"
|
||||
v-if="!forbid && (!isReading || isDownloaded)">
|
||||
<div class="form-group" style="margin-right: 10px">
|
||||
<div :id="`directoryInputWrapper_${scope.row.Id}`" class="btn btn-link file-input">
|
||||
<el-button circle icon="el-icon-upload2" :disabled="btnLoading" :loading="btnLoading"
|
||||
@@ -59,17 +61,15 @@
|
||||
scope.row.UploadStudyList.length <= 0
|
||||
" @click.stop="handleViewReadingImages(scope.row)" :title="$t('upload:dicom:button:preview')" />
|
||||
<!--删除--->
|
||||
<el-button circle :disabled="!scope.row.UploadStudyList ||
|
||||
scope.row.UploadStudyList.length <= 0 ||
|
||||
scope.row.ReadingTaskState === 2
|
||||
" icon="el-icon-delete" :title="$t('upload:dicom:button:delete')" @click.stop="remove(scope.row)" />
|
||||
<el-button circle icon="el-icon-delete" :title="$t('upload:dicom:button:delete')"
|
||||
@click.stop="remove(scope.row)" />
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<div style="margin: 10px 0" class="top">
|
||||
<span>{{ $t('upload:dicom:uploadTitle') }}</span>
|
||||
<div class="btnBox" v-if="!forbid">
|
||||
<div class="btnBox" v-if="!forbid && (!isReading || isDownloaded)">
|
||||
<span style="margin-right: 10px">{{ $store.state.trials.uploadTip }}</span>
|
||||
<form id="inputForm" ref="uploadForm" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
@@ -378,6 +378,14 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
StudyInstanceUID: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'study-view': studyView,
|
||||
@@ -427,7 +435,8 @@ export default {
|
||||
openSubjectVisitId: null,
|
||||
openVisitTaskId: null,
|
||||
TrialModality: [],
|
||||
IsReadingTaskViewInOrder: 2
|
||||
IsReadingTaskViewInOrder: 2,
|
||||
isDownloaded: false
|
||||
}
|
||||
},
|
||||
async mounted() {
|
||||
@@ -470,6 +479,7 @@ export default {
|
||||
let res = await getSubjectImageUploadList(params)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.isDownloaded = res.OtherInfo.IsIRImageDownloaded
|
||||
this.TrialModality = res.OtherInfo.TrialModality.split('|')
|
||||
this.IsReadingTaskViewInOrder = res.OtherInfo.IsReadingTaskViewInOrder || res.OtherInfo.IsReadingTaskViewInOrder === 0 ? res.OtherInfo.IsReadingTaskViewInOrder : 2
|
||||
this.StudyInstanceUidList = []
|
||||
@@ -553,6 +563,7 @@ export default {
|
||||
this.openVisitTaskId = item.VisitTaskId
|
||||
this.model_cfg.title = `${item.SubjectCode || ''} > ${this.IsImageSegment ? item.VisitName : item.TaskBlindName
|
||||
}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.model_cfg.title = ''
|
||||
this.modelList = item[list]
|
||||
this.model_cfg.visible = true
|
||||
},
|
||||
@@ -946,7 +957,7 @@ export default {
|
||||
var instanceItem = instanceList.find(function (item) {
|
||||
return item.instanceUid === instanceUid
|
||||
})
|
||||
if (!instanceItem) {
|
||||
if (!false) {
|
||||
var date = data.string('x00080023')
|
||||
var time = data.string('x00080033')
|
||||
var instanceTime = ''
|
||||
@@ -1075,11 +1086,12 @@ export default {
|
||||
async verifyStudy() {
|
||||
this.btnLoading = true
|
||||
var studyList = []
|
||||
let scope = this
|
||||
this.selectArr.forEach((item) => {
|
||||
item.dicomInfo.uploadFileSize = 0
|
||||
if (!item.uploadState.selected) {
|
||||
studyList.push({
|
||||
studyInstanceUid: item.dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.isReading && scope.StudyInstanceUID ? scope.StudyInstanceUID : item.dicomInfo.studyUid,
|
||||
studyDate: item.dicomInfo.studyTime,
|
||||
})
|
||||
}
|
||||
@@ -1174,7 +1186,7 @@ export default {
|
||||
let t = setInterval(() => {
|
||||
dicomUploadInProgress({
|
||||
trialId: scope.trialId,
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.isReading && scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
VisitTaskId: dicomInfo.visitTaskId,
|
||||
}).then((res) => {
|
||||
console.log(dicomInfo.visitTaskId)
|
||||
@@ -1201,7 +1213,7 @@ export default {
|
||||
dicomInfo.RadiopharmaceuticalStartTime,
|
||||
|
||||
studyId: dicomInfo.studyId,
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.isReading && scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
studyTime: dicomInfo.studyTime,
|
||||
description: dicomInfo.description,
|
||||
seriesCount: dicomInfo.seriesNum,
|
||||
@@ -1242,22 +1254,171 @@ export default {
|
||||
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) {
|
||||
// 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,
|
||||
// SOPClassUID: o.SOPClassUID,
|
||||
// TransferSytaxUID: o.TransferSytaxUID,
|
||||
// MediaStorageSOPInstanceUID:
|
||||
// o.MediaStorageSOPInstanceUID,
|
||||
// MediaStorageSOPClassUID:
|
||||
// o.MediaStorageSOPClassUID,
|
||||
// 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,
|
||||
|
||||
// PhotometricInterpretation:
|
||||
// o.PhotometricInterpretation,
|
||||
// BitsAllocated: o.BitsAllocated,
|
||||
// PixelRepresentation: o.PixelRepresentation,
|
||||
// RescaleIntercept: o.RescaleIntercept,
|
||||
// RescaleSlope: o.RescaleSlope,
|
||||
// ImagePositionPatient: o.ImagePositionPatient,
|
||||
// ImageOrientationPatient:
|
||||
// o.ImageOrientationPatient,
|
||||
// SequenceOfUltrasoundRegions:
|
||||
// o.SequenceOfUltrasoundRegions,
|
||||
// FrameTime: o.FrameTime,
|
||||
// CorrectedImage: o.CorrectedImage,
|
||||
// Units: o.Units,
|
||||
// DecayCorrection: o.DecayCorrection,
|
||||
// EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
// })
|
||||
// Record.Uploaded.push(name)
|
||||
// dicomInfo.failedFileCount++
|
||||
// Record.FileCount++
|
||||
// }
|
||||
// else {
|
||||
let path = `/${params.trialId}/Image/${params.subjectId
|
||||
}/${params.subjectVisitId}/${dicomInfo.visitTaskId
|
||||
}/${scope.getGuid(
|
||||
dicomInfo.studyUid +
|
||||
v.seriesUid +
|
||||
o.instanceUid +
|
||||
params.trialId
|
||||
)}`
|
||||
if (scope.IsImageSegment) {
|
||||
path = `/${params.trialId}/Image/${params.subjectId
|
||||
}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId
|
||||
}/${scope.getGuid(
|
||||
dicomInfo.studyUid +
|
||||
v.seriesUid +
|
||||
o.instanceUid +
|
||||
params.trialId
|
||||
)}`
|
||||
}
|
||||
if (scope.isClose) return
|
||||
let res = await dcmUpload(
|
||||
{
|
||||
path: path,
|
||||
file: o.file,
|
||||
speed: true,
|
||||
},
|
||||
scope.isReading && scope.StudyInstanceUID ? {
|
||||
AnonymizeFixedList: [
|
||||
{
|
||||
Element: '000D',
|
||||
Group: '0020',
|
||||
ReplaceValue: scope.StudyInstanceUID,
|
||||
Id: 'StudyInstanceUID'
|
||||
}
|
||||
],
|
||||
AnonymizeNotFixedList: [],
|
||||
DicomStoreInfo: {}
|
||||
} : null,
|
||||
(percentage, checkpoint, lastPer) => {
|
||||
dicomInfo.uploadFileSize +=
|
||||
checkpoint.size * (percentage - lastPer)
|
||||
if (
|
||||
dicomInfo.uploadFileSize > dicomInfo.fileSize
|
||||
) {
|
||||
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: o.file.name,
|
||||
fileSize: o.file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 5,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (!res || !res.url) {
|
||||
params.failedFileCount++
|
||||
} else {
|
||||
if (ii === 0 && o.modality !== 'SR') {
|
||||
try {
|
||||
let fileId =
|
||||
cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||
o.file
|
||||
)
|
||||
let blob = await scope.dicomToPng(
|
||||
fileId,
|
||||
o.imageColumns,
|
||||
o.imageRows
|
||||
)
|
||||
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
|
||||
if (scope.IsImageSegment) {
|
||||
thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
|
||||
}
|
||||
let OSSclient = scope.OSSclient
|
||||
let seriesRes = await OSSclient.put(
|
||||
thumbnailPath,
|
||||
blob,
|
||||
{
|
||||
fileName: `${v.seriesUid}.jpg`,
|
||||
fileSize: blob.size,
|
||||
fileType: 'image/jpeg',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 6,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (seriesRes && seriesRes.url) {
|
||||
ImageResizePath = scope.$getObjectName(
|
||||
seriesRes.url
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res && res.url) {
|
||||
instanceList.push({
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.isReading && scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
seriesInstanceUid: v.seriesUid,
|
||||
sopInstanceUid: o.instanceUid,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
MediaStorageSOPInstanceUID:
|
||||
o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID:
|
||||
o.MediaStorageSOPClassUID,
|
||||
sopInstanceUid: o.instanceUid,
|
||||
instanceNumber: o.instanceNumber,
|
||||
instanceTime: o.instanceTime,
|
||||
imageRows: o.imageRows,
|
||||
@@ -1270,7 +1431,7 @@ export default {
|
||||
frameOfReferenceUID: o.frameOfReferenceUID,
|
||||
windowCenter: o.windowCenter,
|
||||
windowWidth: o.windowWidth,
|
||||
path: o.myPath,
|
||||
path: scope.$getObjectName(res.url),
|
||||
FileSize: o.FileSize,
|
||||
|
||||
PhotometricInterpretation:
|
||||
@@ -1290,151 +1451,15 @@ export default {
|
||||
DecayCorrection: o.DecayCorrection,
|
||||
EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
})
|
||||
o.myPath = scope.$getObjectName(res.url)
|
||||
Record.Uploaded.push(name)
|
||||
dicomInfo.failedFileCount++
|
||||
Record.FileCount++
|
||||
} else {
|
||||
let path = `/${params.trialId}/Image/${params.subjectId
|
||||
}/${params.subjectVisitId}/${dicomInfo.visitTaskId
|
||||
}/${scope.getGuid(
|
||||
dicomInfo.studyUid +
|
||||
v.seriesUid +
|
||||
o.instanceUid +
|
||||
params.trialId
|
||||
)}`
|
||||
if (scope.IsImageSegment) {
|
||||
path = `/${params.trialId}/Image/${params.subjectId
|
||||
}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId
|
||||
}/${scope.getGuid(
|
||||
dicomInfo.studyUid +
|
||||
v.seriesUid +
|
||||
o.instanceUid +
|
||||
params.trialId
|
||||
)}`
|
||||
}
|
||||
if (scope.isClose) return
|
||||
let res = await dcmUpload(
|
||||
{
|
||||
path: path,
|
||||
file: o.file,
|
||||
speed: true,
|
||||
},
|
||||
null,
|
||||
(percentage, checkpoint, lastPer) => {
|
||||
dicomInfo.uploadFileSize +=
|
||||
checkpoint.size * (percentage - lastPer)
|
||||
if (
|
||||
dicomInfo.uploadFileSize > dicomInfo.fileSize
|
||||
) {
|
||||
dicomInfo.uploadFileSize = dicomInfo.fileSize
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: o.file.name,
|
||||
fileSize: o.file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 5,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (!res || !res.url) {
|
||||
params.failedFileCount++
|
||||
} else {
|
||||
if (ii === 0 && o.modality !== 'SR') {
|
||||
try {
|
||||
let fileId =
|
||||
cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||
o.file
|
||||
)
|
||||
let blob = await scope.dicomToPng(
|
||||
fileId,
|
||||
o.imageColumns,
|
||||
o.imageRows
|
||||
)
|
||||
let thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
|
||||
if (scope.IsImageSegment) {
|
||||
thumbnailPath = `/${params.trialId}/Image/${params.subjectId}/${params.subjectVisitId}/AnnotationImage/${dicomInfo.visitTaskId}/${dicomInfo.studyUid}/${v.seriesUid}.jpg`
|
||||
}
|
||||
let OSSclient = scope.OSSclient
|
||||
let seriesRes = await OSSclient.put(
|
||||
thumbnailPath,
|
||||
blob,
|
||||
{
|
||||
fileName: `${v.seriesUid}.jpg`,
|
||||
fileSize: blob.size,
|
||||
fileType: 'image/jpeg',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 6,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
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,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
MediaStorageSOPInstanceUID:
|
||||
o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID:
|
||||
o.MediaStorageSOPClassUID,
|
||||
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,
|
||||
|
||||
PhotometricInterpretation:
|
||||
o.PhotometricInterpretation,
|
||||
BitsAllocated: o.BitsAllocated,
|
||||
PixelRepresentation: o.PixelRepresentation,
|
||||
RescaleIntercept: o.RescaleIntercept,
|
||||
RescaleSlope: o.RescaleSlope,
|
||||
ImagePositionPatient: o.ImagePositionPatient,
|
||||
ImageOrientationPatient:
|
||||
o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions:
|
||||
o.SequenceOfUltrasoundRegions,
|
||||
FrameTime: o.FrameTime,
|
||||
CorrectedImage: o.CorrectedImage,
|
||||
Units: o.Units,
|
||||
DecayCorrection: o.DecayCorrection,
|
||||
EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
})
|
||||
o.myPath = scope.$getObjectName(res.url)
|
||||
Record.Uploaded.push(name)
|
||||
dicomInfo.failedFileCount++
|
||||
Record.FileCount++
|
||||
} else {
|
||||
Record.Failed.push(name)
|
||||
Record.FileCount++
|
||||
}
|
||||
Record.Failed.push(name)
|
||||
Record.FileCount++
|
||||
}
|
||||
// }
|
||||
resolve1()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
@@ -1452,7 +1477,7 @@ export default {
|
||||
}
|
||||
}
|
||||
params.study.seriesList.push({
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.isReading && scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
seriesInstanceUid: v.seriesUid,
|
||||
seriesNumber: v.seriesNumber,
|
||||
seriesTime: v.seriesTime,
|
||||
@@ -1642,7 +1667,7 @@ export default {
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showvisitdicoms?page=upload&trialId=${trialId}&visitTaskId=${this.IsImageSegment ? 'undefined' : row.VisitTaskId
|
||||
}&subjectVisitId=${row.SourceSubjectVisitId
|
||||
}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
}&isReading=1&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
<el-tab-pane :label="$t('uploadDicomAndNonedicom:label:dicom')" name="dicom">
|
||||
<dicomFile v-if="activeName === 'dicom'" :SubjectId="SubjectId" :SubjectCode="SubjectCode"
|
||||
:Criterion="Criterion" :TaskId="VisitTaskId" :isUpload.sync="isUpload"
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :IsImageSegment="IsImageSegment" :forbid="forbid" />
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :IsImageSegment="IsImageSegment" :forbid="forbid"
|
||||
:isReading="isReading" :StudyInstanceUID="StudyInstanceUID" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('uploadDicomAndNonedicom:label:nonedicom')" name="nonedicom">
|
||||
<nonedicomFile v-if="activeName === 'nonedicom'" :SubjectId="SubjectId" :SubjectCode="SubjectCode"
|
||||
:Criterion="Criterion" :VisitTaskId="VisitTaskId" :isUpload.sync="isUpload" :IsImageSegment="IsImageSegment"
|
||||
:forbid="forbid" />
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :forbid="forbid" :isReading="isReading" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
@@ -58,6 +59,14 @@ export default {
|
||||
IsImageSegment: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
StudyInstanceUID: {
|
||||
type: String,
|
||||
default: '',
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -70,6 +79,7 @@ export default {
|
||||
mounted() {
|
||||
this.title = `Upload Images:${this.SubjectCode}(${this.Criterion.TrialReadingCriterionName})`
|
||||
if (this.IsImageSegment) this.title = `Upload Images:${this.SubjectCode}`
|
||||
if (this.isReadingTaskViewInOrder === 0) this.title = ''
|
||||
store.dispatch('trials/setUnLock', true)
|
||||
},
|
||||
methods: {
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
<el-table :data="list" style="width: 100%" v-adaptive="{ bottomOffset: 60 }" :loading="loading"
|
||||
:default-sort="{ prop: 'TaskBlindName', order: 'descending' }">
|
||||
<!--受试者 sortable="custom"-->
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')" />
|
||||
<el-table-column prop="SubjectCode" :label="$t('upload:nonedicom:table:subject')"
|
||||
v-if="isReadingTaskViewInOrder !== 0" />
|
||||
<!--访视名称-->
|
||||
<el-table-column prop="VisitName" :label="$t('upload:nonedicom:table:VisitName')" sortable
|
||||
v-if="IsImageSegment" />
|
||||
@@ -110,11 +111,9 @@
|
||||
:title="$t('upload:nonedicom:button:preview')" @click.stop="handlePreviewNoneDicomFiles(scope.row)" />
|
||||
<!--上传--->
|
||||
<el-button circle icon="el-icon-upload2" :title="$t('upload:nonedicom:button:upload')" v-if="!forbid"
|
||||
@click.native.prevent="handleUpload(scope.row)" />
|
||||
@click.native.prevent="handleUpload(scope.row)" :disabled="isReading && !isDownloaded" />
|
||||
<!--删除--->
|
||||
<el-button :disabled="scope.row.UploadedFileCount <= 0 ||
|
||||
scope.row.ReadingTaskState === 2
|
||||
" circle icon="el-icon-delete" :title="$t('upload:nonedicom:button:delete')"
|
||||
<el-button circle icon="el-icon-delete" :title="$t('upload:nonedicom:button:delete')"
|
||||
@click.stop="remove(scope.row)" />
|
||||
</template>
|
||||
</el-table-column>
|
||||
@@ -265,6 +264,14 @@ export default {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
isReading: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -286,7 +293,8 @@ export default {
|
||||
BodyPart: {},
|
||||
relationInfo: {
|
||||
ImageFormatList: []
|
||||
}
|
||||
},
|
||||
isDownloaded: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@@ -343,6 +351,7 @@ export default {
|
||||
if (res.IsSuccess) {
|
||||
this.list = res.Result
|
||||
this.relationInfo = res.OtherInfo
|
||||
this.isDownloaded = res.OtherInfo.IsIRImageDownloaded
|
||||
this.faccept = []
|
||||
this.relationInfo.ImageFormatList.forEach((item) => {
|
||||
this.faccept.push(`.${item}`)
|
||||
@@ -475,7 +484,7 @@ export default {
|
||||
let trialId = this.$route.query.trialId
|
||||
var token = getToken()
|
||||
const routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&subjectVisitId=${row.SourceSubjectVisitId}&studyId=${row.Id}&visitTaskId=${row.VisitTaskId}&TokenKey=${token}&IsReadingTaskViewInOrder=${this.isReadingTaskViewInOrder}`,
|
||||
})
|
||||
this.open = window.open(routeData.href, '_blank')
|
||||
},
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
</el-button>
|
||||
<el-table :data="modelList" style="width: 100%" height="300">
|
||||
<!--检查编号-->
|
||||
<el-table-column prop="StudyCode" :label="$t('trials:uploadImage:table:StudyCode')" />
|
||||
<el-table-column prop="StudyCode" :label="$t('trials:uploadImage:table:StudyCode')"
|
||||
v-if="IsReadingTaskViewInOrder !== 0" />
|
||||
<!--检查类型-->
|
||||
<el-table-column prop="ModalityForEdit" :label="$t('trials:uploadImage:table:ModalityForEdit')"
|
||||
v-if="IsDicom" />
|
||||
@@ -187,11 +188,11 @@ export default {
|
||||
var token = getToken()
|
||||
if (!this.IsImageSegment && (this.Criterion.CriterionType == 19 || this.Criterion.CriterionType == 20)) {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&isImageSegmentLabel=${false}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
})
|
||||
} else {
|
||||
routeData = this.$router.resolve({
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true`,
|
||||
path: `/showNoneDicoms?trialId=${trialId}&visitTaskId=${this.visitTaskId}&subjectVisitId=${this.subjectVisitId}&TokenKey=${token}&isReading=true&IsReadingTaskViewInOrder=${this.IsReadingTaskViewInOrder}`,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+7
-2
@@ -92,8 +92,13 @@ router.beforeEach(async (to, from, next) => {
|
||||
await store.dispatch('user/getUserInfo')
|
||||
const accessRoutes = await store.dispatch('permission/generateRoutes')
|
||||
resetRouter()
|
||||
router.addRoutes(accessRoutes)
|
||||
next({ ...to, replace: true })
|
||||
if (accessRoutes.length > 0) {
|
||||
router.addRoutes(accessRoutes)
|
||||
next({ ...to, replace: true })
|
||||
} else {
|
||||
next()
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
// 删除token并进入登录页面以重新登录
|
||||
|
||||
@@ -149,6 +149,11 @@ export const constantRoutes = [
|
||||
hidden: true,
|
||||
component: () => import('@/views/trials/trials-panel/reading/dicoms/none-dicoms')
|
||||
},
|
||||
{
|
||||
path: '/ecrfList',
|
||||
hidden: true,
|
||||
component: () => import('@/views/trials/trials-panel/reading/dicoms/components/TableList')
|
||||
},
|
||||
{
|
||||
path: '/readingPage',
|
||||
name: 'readingPage',
|
||||
|
||||
@@ -376,4 +376,8 @@ body .el-table th.gutter {
|
||||
height: 20px !important;
|
||||
vertical-align: -0.4em !important;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.mobile_confirm {
|
||||
width: 200px;
|
||||
}
|
||||
@@ -6,6 +6,7 @@ export const anonymization = function (file, config) {
|
||||
try {
|
||||
const reader = new FileReader()
|
||||
let AnonymizeFixedList = config.AnonymizeFixedList
|
||||
console.log(AnonymizeFixedList, 'AnonymizeFixedList')
|
||||
let AnonymizeNotFixedList = config.AnonymizeNotFixedList
|
||||
let DicomStoreInfo = config.DicomStoreInfo
|
||||
reader.onload = async (event) => {
|
||||
@@ -15,9 +16,11 @@ export const anonymization = function (file, config) {
|
||||
let dataset = dcmjs.data.DicomMessage.readFile(buffer)
|
||||
for (var i = 0; i < AnonymizeFixedList.length; i++) {
|
||||
let AnonymizeFixed = AnonymizeFixedList[i]
|
||||
if (!dataset.dict.hasOwnProperty(`${AnonymizeFixed.Group + AnonymizeFixed.Element}`)) continue
|
||||
if (!dataset.dict.hasOwnProperty(`${AnonymizeFixed.Group + AnonymizeFixed.Element}`) && !dataset.meta.hasOwnProperty(`${AnonymizeFixed.Group + AnonymizeFixed.Element}`)) continue
|
||||
if (dataset.dict[AnonymizeFixed.Group + AnonymizeFixed.Element]) {
|
||||
dataset.dict[AnonymizeFixed.Group + AnonymizeFixed.Element].Value[0] = AnonymizeFixed.ReplaceValue
|
||||
} else if (dataset.meta[AnonymizeFixed.Group + AnonymizeFixed.Element]) {
|
||||
dataset.meta[AnonymizeFixed.Group + AnonymizeFixed.Element].Value[0] = AnonymizeFixed.ReplaceValue
|
||||
} else {
|
||||
dataset.dict[AnonymizeFixed.Group + AnonymizeFixed.Element] = {
|
||||
vr: AnonymizeFixed.ValueRepresentation,
|
||||
@@ -60,7 +63,7 @@ export const anonymization = function (file, config) {
|
||||
let newDicomFile = dataset.write() // fragmentMultiframe 原始数据是否进行分割
|
||||
const bufferArray = new Uint8Array(newDicomFile)
|
||||
const blob = new Blob([bufferArray], { type: 'application/octet-stream' })
|
||||
resolve({ blob, pixelDataElement })
|
||||
resolve({ blob, pixelDataElement, Modality: dataset.dict['00080060'].Value[0] })
|
||||
} catch (err) {
|
||||
console.log(file, 'warning')
|
||||
console.log(err)
|
||||
|
||||
@@ -12,7 +12,8 @@ export const dcmUpload = async function (data, config, progressFn, fileInfo) {
|
||||
let res = await Vue.prototype.OSSclient.multipartUpload(Object.assign(data, { file: blob.blob }), progressFn, fileInfo)
|
||||
resolve({
|
||||
...res,
|
||||
image: blob.pixelDataElement
|
||||
image: blob.pixelDataElement,
|
||||
Modality: blob.Modality
|
||||
})
|
||||
// let OSSclientA = await OSSclient
|
||||
// let blob = await encoder(file)
|
||||
|
||||
+17
-17
@@ -40,7 +40,7 @@ async function ossGenerateSTS() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
let _vm = router.default.app
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload' && _vm._route.path !== '/readingDicoms' && _vm._route.path !== '/showdicom') {
|
||||
var objectItem = objectName.split('/')
|
||||
// objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
|
||||
objectItem[objectItem.length - 1] = `${objectItem[objectItem.length - 1].substring(
|
||||
@@ -57,13 +57,13 @@ async function ossGenerateSTS() {
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: objectName}, fileInfo)
|
||||
let params = Object.assign({ path: objectName }, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = objectName.split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: objectName, fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
@@ -97,7 +97,7 @@ async function ossGenerateSTS() {
|
||||
OSSclient = new OSS(Vue.prototype.OSSclientConfig);
|
||||
}
|
||||
let _vm = router.default.app
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload' && _vm._route.path !== '/readingDicoms' && _vm._route.path !== '/showdicom') {
|
||||
var objectItem = data.path.split('/')
|
||||
// objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
|
||||
objectItem[objectItem.length - 1] = `${objectItem[objectItem.length - 1].substring(
|
||||
@@ -114,17 +114,17 @@ async function ossGenerateSTS() {
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: data.path}, fileInfo)
|
||||
let params = Object.assign({ path: data.path }, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = data.path.split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: data.path, fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
|
||||
|
||||
resolve({
|
||||
name: data.path,
|
||||
url: Vue.prototype.OSSclientConfig.viewEndpoint + decodeUtf8(res.name)
|
||||
@@ -151,7 +151,7 @@ async function ossGenerateSTS() {
|
||||
try {
|
||||
var name = objectName.split('/')[objectName.split('/').length - 1]
|
||||
let _vm = router.default.app
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload' && _vm._route.path !== '/readingDicoms' && _vm._route.path !== '/showdicom') {
|
||||
var objectItem = objectName.split('/')
|
||||
objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
|
||||
objectName = objectItem.join('/')
|
||||
@@ -225,7 +225,7 @@ function uploadAWS(aws, data, progress, fileInfo) {
|
||||
const { file, path } = data;
|
||||
if (!file || !path) return reject('file and path be required');
|
||||
let _vm = router.default.app
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload') {
|
||||
if (_vm._route.path !== '/trials/trials-panel/visit/crc-upload' && _vm._route.path !== '/readingDicoms' && _vm._route.path !== '/showdicom') {
|
||||
var objectItem = data.path.split('/')
|
||||
// objectItem[objectItem.length - 1] = new Date().getTime() + '_' + objectItem[objectItem.length - 1]
|
||||
objectItem[objectItem.length - 1] = `${objectItem[objectItem.length - 1].substring(
|
||||
@@ -246,13 +246,13 @@ function uploadAWS(aws, data, progress, fileInfo) {
|
||||
const trialId = urlParams.get('trialId')
|
||||
if (Object.keys(fileInfo).length !== 0) {
|
||||
fileInfo.fileType = mimeTypeToExt(fileInfo.fileType)
|
||||
let params = Object.assign({path: decodeUtf8(curPath)}, fileInfo)
|
||||
let params = Object.assign({ path: decodeUtf8(curPath) }, fileInfo)
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
} else if (trialId) {
|
||||
const fileName = decodeUtf8(curPath).split('/').pop()
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
const fileType = fileName.includes('.')
|
||||
? fileName.split('.').pop().toLowerCase()
|
||||
: ''
|
||||
let params = { trialId, path: decodeUtf8(curPath), fileName, fileType }
|
||||
addOrUpdateFileUploadRecord(params)
|
||||
}
|
||||
|
||||
@@ -118,6 +118,9 @@ service.interceptors.response.use(
|
||||
if (res.IsSuccess) {
|
||||
return Promise.resolve(res)
|
||||
} else if (res.IsSuccess === false) {
|
||||
if (res.Code === -4) {
|
||||
return Promise.resolve(res)
|
||||
}
|
||||
if (res.Code !== 5) {
|
||||
MessageBox.confirm(res.ErrorMessage, {
|
||||
type: 'warning',
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
const WHITELIST = ['/', "/curriculumVitae", 'researchDetail_m', '/researchForm', '/ReviewersResearch', '/login', '/link_expired', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms']
|
||||
const WHITELIST = ['/', "/curriculumVitae", 'researchDetail_m', '/researchForm', '/ReviewersResearch', '/login', '/link_expired', '/error', '/resetpassword', '/recompose', '/email-recompose', '/trialStats', '/showdicom', '/imagesShare', '/audit', '/preview', '/researchLogin', '/researchLogin_m', '/blindResumeInfo', '/trialsResume', '/joinVerify', '/showNoneDicoms', '/noneDicomReading', '/clinicalData', '/readingDicoms', '/readingPage', '/visitDicomReview', '/visitNondicomReview', '/globalReview', '/adReview', '/oncologyReview', '/nonedicoms', '/ecrfList']
|
||||
export default WHITELIST
|
||||
|
||||
@@ -125,7 +125,8 @@
|
||||
</div>
|
||||
<div class="viewerContent">
|
||||
<dicom-viewer id="dicomViewer" ref="dicomViewer" style="height:100%" :loading.sync="loading"
|
||||
:modality="modality" :Comparison.sync="isComparison" @loadStudy="loadStudy" />
|
||||
:modality="modality" :Comparison.sync="isComparison" :SeriesList="seriesList"
|
||||
:currentSeriesIndex="currentSeriesIndex" @loadStudy="loadStudy" />
|
||||
</div>
|
||||
<!-- <div class="viewerRightSidePanel">
|
||||
<dicom-tools />
|
||||
@@ -179,7 +180,7 @@ export default {
|
||||
description: '',
|
||||
seriesCount: 0,
|
||||
seriesList: [],
|
||||
currentSeriesIndex: -1,
|
||||
currentSeriesIndex: 0,
|
||||
arr: [],
|
||||
activeName: 'first',
|
||||
tpList: [],
|
||||
@@ -253,6 +254,11 @@ export default {
|
||||
})
|
||||
workSpeedclose(true)
|
||||
},
|
||||
watch: {
|
||||
currentSeriesIndex() {
|
||||
console.log(this.currentSeriesIndex, 'currentSeriesIndex')
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async updateImageResizePath(data) {
|
||||
try {
|
||||
@@ -353,13 +359,14 @@ export default {
|
||||
i.ImageId = imageId
|
||||
}
|
||||
})
|
||||
var subjectVisitId = this.$router.currentRoute.query.subjectVisitId
|
||||
var subjectVisitId = this.$router.currentRoute.query.subjectVisitId ? this.$router.currentRoute.query.subjectVisitId : item.SubjectVisitId
|
||||
var studyId = this.$router.currentRoute.query.studyId
|
||||
var trialId = this.$router.currentRoute.query.trialId
|
||||
seriesList.push({
|
||||
trialId,
|
||||
subjectVisitId,
|
||||
studyId,
|
||||
subjectId: item.SubjectId,
|
||||
imageIds: imageIds,
|
||||
instanceInfoList: item.InstanceInfoList,
|
||||
seriesId: item.Id,
|
||||
@@ -415,12 +422,13 @@ export default {
|
||||
i.ImageId = imageId
|
||||
}
|
||||
})
|
||||
var subjectVisitId = this.$router.currentRoute.query.subjectVisitId
|
||||
var subjectVisitId = this.$router.currentRoute.query.subjectVisitId ? this.$router.currentRoute.query.subjectVisitId : item.SubjectVisitId
|
||||
var studyId = this.$router.currentRoute.query.studyId
|
||||
var trialId = this.$router.currentRoute.query.trialId
|
||||
seriesList.push({
|
||||
trialId,
|
||||
subjectVisitId,
|
||||
subjectId: item.SubjectId,
|
||||
studyId,
|
||||
imageIds: imageIds,
|
||||
instanceInfoList: item.InstanceInfoList,
|
||||
@@ -1197,6 +1205,7 @@ export default {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
:name="`${study.StudyId}`">
|
||||
<template slot="title">
|
||||
<div class="collapse-title-wrapper">
|
||||
<div class="text-desc">
|
||||
<div class="text-desc" v-if="IsReadingTaskViewInOrder !== 0">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
@@ -157,7 +157,7 @@
|
||||
</el-tab-pane>
|
||||
<el-tab-pane v-show="!visitTaskId" v-if="IsReadingTaskViewInOrder >= 2"
|
||||
:label="$t('trials:dicom-show:relatedVisit')" name="relation-study" class="pane-relation-wrapper">
|
||||
<div class="viewerSidethumbinner">
|
||||
<div class="viewerSidethumbinner">
|
||||
|
||||
<el-collapse v-model="relationActiveName" @change="handelRelationActiveChange">
|
||||
<div v-for="item in relationStudyListByVisitName" :key="`${item.VisitName}`">
|
||||
@@ -169,7 +169,7 @@
|
||||
v-if="study.VisitName === item.VisitName">
|
||||
<template slot="title">
|
||||
<div class="collapse-title-wrapper">
|
||||
<div class="text-desc">
|
||||
<div class="text-desc" v-if="IsReadingTaskViewInOrder !== 0">
|
||||
{{ study.StudyCode }}
|
||||
</div>
|
||||
<!-- <div v-show="study.Description" class="text-desc">
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="wscn-http404-container">
|
||||
<div class="wscn-http404" style="display: flex;align-items: center">
|
||||
<div class="wscn-http404" style="display: flex;align-items: center;flex-wrap: wrap;justify-content: center;">
|
||||
<div class="pic-404">
|
||||
<!-- <img class="pic-404__parent" src="@/assets/login-bg.png" alt="404"> -->
|
||||
<svg-icon icon-class="login-bg" style="width: 100%; height: 100%" />
|
||||
@@ -55,18 +55,20 @@ export default {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wscn-http404 {
|
||||
position: relative;
|
||||
width: 1200px;
|
||||
width: 100%;
|
||||
padding: 0 50px;
|
||||
overflow: hidden;
|
||||
|
||||
.pic-404 {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 500px;
|
||||
width: 100%;
|
||||
max-width: 500px;
|
||||
height: 300px;
|
||||
overflow: hidden;
|
||||
margin-right: 10px;
|
||||
@@ -211,6 +213,7 @@ export default {
|
||||
animation-name: slideUp;
|
||||
animation-duration: 0.5s;
|
||||
animation-fill-mode: forwards;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__headline {
|
||||
|
||||
@@ -153,7 +153,8 @@ export default {
|
||||
isAudit: false,
|
||||
|
||||
activeNames: [],
|
||||
Asc: false
|
||||
Asc: false,
|
||||
IsReadingTaskViewInOrder: 2
|
||||
}
|
||||
},
|
||||
async created() {
|
||||
@@ -165,6 +166,9 @@ export default {
|
||||
store.dispatch('user/setToken', this.$router.currentRoute.query.TokenKey)
|
||||
changeURLStatic('TokenKey', '')
|
||||
}
|
||||
if (this.$router.currentRoute.query.IsReadingTaskViewInOrder) {
|
||||
this.IsReadingTaskViewInOrder = Number(this.$router.currentRoute.query.IsReadingTaskViewInOrder)
|
||||
}
|
||||
this.subjectVisitId = this.$router.currentRoute.query.subjectVisitId
|
||||
this.studyId = this.$router.currentRoute.query.studyId
|
||||
this.getNoneDicomList()
|
||||
|
||||
@@ -50,6 +50,9 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="v.fileType.includes('zip')" class="content flex_col">
|
||||
<img :title="v.FileName" crossorigin="anonymous" :src="zipImg" height="100%"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="Anonymous" v-if="isAnonymous">
|
||||
@@ -158,6 +161,7 @@ import hardcodedMetaDataProvider from '@/views/trials/trials-panel/reading/visit
|
||||
import registerWebImageLoader from '@/views/trials/trials-panel/reading/visit-review/js/registerWebImageLoader'
|
||||
import Note_RectangleRoiTool from '@/views/trials/trials-panel/reading/dicoms3D/components/tools/Note_RectangleRoiTool'
|
||||
import { noneDicomStudyMaskImage, noneDicomStudyUndoMaskImage } from "@/api/reading"
|
||||
import zipImg from '@/assets/zip.png'
|
||||
const { ViewportType } = Enums
|
||||
const renderingEngineId = 'myRenderingEngine'
|
||||
const {
|
||||
@@ -221,7 +225,7 @@ export default {
|
||||
activeTool: '',
|
||||
imageType: ['image/jpeg', 'image/jpg', 'image/bmp', 'image/png'],
|
||||
loading: false,
|
||||
isFitToWindowMode: false,
|
||||
isFitToWindowMode: true,
|
||||
trialId: null,
|
||||
activeName: '1',
|
||||
tools: [],
|
||||
@@ -231,7 +235,8 @@ export default {
|
||||
tip: [
|
||||
this.$t('DicomViewer:anonymous:after'),
|
||||
this.$t('DicomViewer:anonymous:before')
|
||||
]
|
||||
],
|
||||
zipImg
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
||||
@@ -42,6 +42,9 @@
|
||||
<el-image v-else-if="
|
||||
!!~k.FileType.indexOf('mp4')
|
||||
" style="width: 100%; height: 100%" :src="mp4" fit="contain" crossorigin="anonymous" />
|
||||
<el-image v-else-if="
|
||||
!!~k.FileType.indexOf('zip')
|
||||
" style="width: 100%; height: 100%" :src="zipImg" fit="contain" crossorigin="anonymous" />
|
||||
</div>
|
||||
<div class="file-text" :title="k.FileName">
|
||||
{{ k.FileName }}
|
||||
@@ -73,6 +76,7 @@ import { getNoneDicomStudyList, setNodicomStudyState } from '@/api/trials'
|
||||
import FileNameSorter from "@/utils/customSort"
|
||||
import pdf from '@/assets/pdf.png'
|
||||
import mp4 from '@/assets/mp4.png'
|
||||
import zipImg from '@/assets/zip.jpg'
|
||||
export default {
|
||||
name: 'StudyList',
|
||||
props: {
|
||||
@@ -98,6 +102,7 @@ export default {
|
||||
studyList: [],
|
||||
pdf,
|
||||
mp4,
|
||||
zipImg,
|
||||
BodyPart: {},
|
||||
subjectVisitId: '',
|
||||
studyId: '',
|
||||
|
||||
@@ -25,19 +25,10 @@
|
||||
<div class="login_content">
|
||||
<div class="form-label-width">
|
||||
<el-form-item :label="$t('trials:researchForm:form:siteName')" prop="TrialSiteId">
|
||||
<el-select
|
||||
v-model="form.TrialSiteId"
|
||||
filterable
|
||||
style="width:100%;"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
@change="handleSiteChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item,index) of siteOptions"
|
||||
:key="index"
|
||||
:label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId"
|
||||
/>
|
||||
<el-select v-model="form.TrialSiteId" filterable style="width:100%;"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" @change="handleSiteChange">
|
||||
<el-option v-for="(item, index) of siteOptions" :key="index" :label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 中心编号 -->
|
||||
@@ -49,74 +40,149 @@
|
||||
<el-input v-model="form.UserName" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 联系电话 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:contactorPhone')"
|
||||
prop="Phone"
|
||||
>
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorPhone')" prop="Phone">
|
||||
<el-input v-model="form.Phone" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 联系邮箱 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')">
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')" prop="Email">
|
||||
<el-input v-model="form.Email" disabled />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('trials:researchForm:form:CommonUploadRecordId')
|
||||
" v-if="IsSupportUploadFile" class="file">
|
||||
<el-input v-model="form.SiteSurveyFile.FileName" type="textarea" :autosize="{ minRows: 1, maxRows: 3 }"
|
||||
style="margin-right: 5px;" disabled />
|
||||
<div class="upload" v-if="!(!(state === 0 && userTypeEnumInt === 0) || isHistory)">
|
||||
<input accept=".pdf,.docx,.doc" type="file" name="uploadFolder" class="select-file" title=""
|
||||
@change="beginScanFiles($event)" />
|
||||
<div class="btn-select">
|
||||
{{ $t('dictionary:template:basicData:button:selectFile') }}
|
||||
</div>
|
||||
</div>
|
||||
<!-- <el-button type="primary" @click="viewManualFile"
|
||||
:disabled="!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path">{{
|
||||
$t('trials:researchForm:form:preview') }}</el-button> -->
|
||||
<el-button type="primary" @click="downLoad"
|
||||
:disabled="!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path">{{
|
||||
$t('trials:researchForm:form:download') }}</el-button>
|
||||
</el-form-item>
|
||||
<!-- 平均刻盘周期(天) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('AverageEngravingCycle')" :label="$t('trials:researchForm:form:engravingCycle')">
|
||||
<el-input-number v-model="form.AverageEngravingCycle" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0" style="width:100%;" />
|
||||
<el-form-item v-if="!notShowFieldList.includes('AverageEngravingCycle')"
|
||||
:label="$t('trials:researchForm:form:engravingCycle')">
|
||||
<el-input-number v-model="form.AverageEngravingCycle"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" controls-position="right" :min="0"
|
||||
style="width:100%;" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
<!-- MRI-PDFF 是否为本中心该适应症的常规诊疗检查项目? -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsRoutineMRIPDEE')"
|
||||
:label="$t('trials:researchForm:form:IsRoutineMRIPDEE')" prop="IsRoutineMRIPDEE">
|
||||
<el-radio-group v-model="form.IsRoutineMRIPDEE"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsRoutineMRIPDEE${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- MRI-PDFF 检查的检测周期(含单次检查时长、预约等待时长等) -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('MRIPDFFScanTime') || !notShowFieldList.includes('MRIPDFFLeadTime') || !notShowFieldList.includes('MRIPDFFOther')"
|
||||
:label="$t('trials:researchForm:form:IsMRIPDFF')">
|
||||
</el-form-item>
|
||||
<!-- 单次检查时长(分钟) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFScanTime')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFScanTime')">
|
||||
<el-input-number v-model="form.MRIPDFFScanTime"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<!-- 平均预约等待时长(天) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFLeadTime')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFLeadTime')">
|
||||
<el-input-number v-model="form.MRIPDFFLeadTime"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" controls-position="right" :min="0" />
|
||||
</el-form-item>
|
||||
<!-- 特殊情况备注-->
|
||||
<el-form-item v-if="!notShowFieldList.includes('MRIPDFFOther')"
|
||||
:label="$t('trials:researchForm:form:MRIPDFFOther')">
|
||||
<el-input v-model="form.MRIPDFFOther" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" />
|
||||
</el-form-item>
|
||||
<!-- 如已选择研究者评估,项目是否会授权影像科老师参与本试验?如不单独授权,是否可在试验中保持 1-2 名固定技师操作?-->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('IsAuthorizeRadiologistsParticipate') || !notShowFieldList.includes('AssignFixedTechnologists')"
|
||||
:label="$t('trials:researchForm:form:IsAuthorize')" prop="IsAuthorize">
|
||||
<el-radio-group v-model="form.IsAuthorize" :disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)"
|
||||
@input="handleIsAuthorizeInput">
|
||||
<el-radio label="IsAuthorizeRadiologistsParticipate">{{
|
||||
$t('trials:researchForm:form:IsAuthorizeRadiologistsParticipate') }}</el-radio>
|
||||
<el-radio label="AssignFixedTechnologists">{{
|
||||
$t('trials:researchForm:form:AssignFixedTechnologists') }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 请确认参与本项目影像采集的影像技师具备对应的资质(如:“技师证”,对应设备的“大型设备上岗证”) -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsConfirmImagingTechnologist')" :label="$t('trials:researchForm:form:isQualified')">
|
||||
<el-radio-group v-model="form.IsConfirmImagingTechnologist" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio
|
||||
v-for="item of $d.YesOrNo"
|
||||
:key="`IsConfirmImagingTechnologist${item.value}`"
|
||||
:label="item.value"
|
||||
>{{ item.label }}</el-radio>
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsConfirmImagingTechnologist')"
|
||||
:label="$t('trials:researchForm:form:isQualified')" prop="IsConfirmImagingTechnologist">
|
||||
<el-radio-group v-model="form.IsConfirmImagingTechnologist"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsConfirmImagingTechnologist${item.value}`"
|
||||
:label="item.value">{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 原因 -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('NotConfirmReson') && form.IsConfirmImagingTechnologist === false"
|
||||
:label="$t('trials:researchForm:form:notQualifiedReason')"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.NotConfirmReson"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
/>
|
||||
:label="$t('trials:researchForm:form:notQualifiedReason')" prop="NotConfirmReson">
|
||||
<el-input v-model="form.NotConfirmReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 研究单位疗效评估人员类型 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('EfficacyEvaluatorType')" :label="$t('trials:researchForm:form:staffType')">
|
||||
<el-radio-group v-model="form.EfficacyEvaluatorType" :disabled="!(state === 0 && userTypeEnumInt === 0)|| isHistory">
|
||||
<el-radio v-for="item of $d.EfficacyEvaluatorType" :key="`EfficacyEvaluatorType${item.value}`" :label="item.value">{{ item.label }}</el-radio>
|
||||
<el-form-item v-if="!notShowFieldList.includes('EfficacyEvaluatorType')"
|
||||
:label="$t('trials:researchForm:form:staffType')">
|
||||
<el-radio-group v-model="form.EfficacyEvaluatorType"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.EfficacyEvaluatorType" :key="`EfficacyEvaluatorType${item.value}`"
|
||||
:label="item.value">{{ item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 是否严格按照研究单位影像手册参数完成图像采集 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsFollowStudyParameters')">
|
||||
<el-form-item v-if="!notShowFieldList.includes('IsFollowStudyParameters')" prop="IsFollowStudyParameters">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:isFollowStudyParam')" />
|
||||
<el-radio-group v-model="form.IsFollowStudyParameters" :disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsFollowStudyParameters${item.value}`" :label="item.value">{{ item.label }}</el-radio>
|
||||
<el-radio-group v-model="form.IsFollowStudyParameters"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`IsFollowStudyParameters${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
<el-button type="primary" size="small" style="margin-left: 5px;" @click="viewManual">
|
||||
{{ $t('trials:researchForm:button:viewManual') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
<!-- 不能严格按照研究单位影像手册参数采集图像原因 -->
|
||||
<el-form-item
|
||||
v-if="!notShowFieldList.includes('NotFollowReson') && !form.IsFollowStudyParameters"
|
||||
>
|
||||
<el-form-item v-if="!notShowFieldList.includes('NotFollowReson') && !form.IsFollowStudyParameters"
|
||||
prop="NotFollowReson">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:notFollowStudyParam')" />
|
||||
<el-input
|
||||
v-model="form.NotFollowReson"
|
||||
type="textarea"
|
||||
:autosize="{ minRows: 2, maxRows: 4}"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory"
|
||||
/>
|
||||
<el-input v-model="form.NotFollowReson" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="!(state === 0 && userTypeEnumInt === 0) || isHistory" />
|
||||
</el-form-item>
|
||||
<!-- 是否严格按照影像手册参数完成刻盘 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('ISStrictManualBurnFlag')" prop="ISStrictManualBurnFlag">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:ISStrictManualBurnFlag')" />
|
||||
<el-radio-group v-model="form.ISStrictManualBurnFlag"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" style="margin-right: 10px;">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="`ISStrictManualBurnFlag${item.value}`" :label="item.value">{{
|
||||
item.label }}</el-radio>
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- 不能严格按照影像手册参数完成刻盘原因 -->
|
||||
<el-form-item v-if="!notShowFieldList.includes('NotStrictManualBurnFlagReason') && !form.ISStrictManualBurnFlag"
|
||||
prop="NotStrictManualBurnFlagReason">
|
||||
<span slot="label" v-html="$t('trials:researchForm:form:NotStrictManualBurnFlagReason')" />
|
||||
<el-input v-model="form.NotStrictManualBurnFlagReason" type="textarea" :autosize="{ minRows: 2, maxRows: 4 }"
|
||||
:disabled="(!(state === 0 && userTypeEnumInt === 0) || isHistory)" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getTrialSiteSelect } from '@/api/trials'
|
||||
import { getTrialSiteSelect, getTrialDocumentList, addOrUpdateCommonUploadRecord } from '@/api/trials'
|
||||
import { addOrUpdateTrialSiteSurvey } from '@/api/research'
|
||||
export default {
|
||||
name: 'ResearchBasicInfo',
|
||||
@@ -124,7 +190,15 @@ export default {
|
||||
isHistory: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
IsOnlyUploadFile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
IsSupportUploadFile: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
data() {
|
||||
var checkPhone = (rule, value, callback) => {
|
||||
@@ -156,16 +230,51 @@ export default {
|
||||
Phone: '', // 联系人电话
|
||||
Email: '', // 联系人邮箱
|
||||
AverageEngravingCycle: '',
|
||||
IsRoutineMRIPDEE: '',
|
||||
MRIPDFFScanTime: '',
|
||||
MRIPDFFLeadTime: '',
|
||||
MRIPDFFOther: '',
|
||||
IsAuthorize: '',
|
||||
IsAuthorizeRadiologistsParticipate: '',
|
||||
AssignFixedTechnologists: '',
|
||||
ISStrictManualBurnFlag: '',
|
||||
NotStrictManualBurnFlagReason: '',
|
||||
IsConfirmImagingTechnologist: '',
|
||||
NotConfirmReson: '',
|
||||
EfficacyEvaluatorType: '',
|
||||
IsFollowStudyParameters: '',
|
||||
NotFollowReson: ''
|
||||
NotFollowReson: '',
|
||||
CommonUploadRecordId: null,
|
||||
SiteSurveyFile: []
|
||||
},
|
||||
rules: {
|
||||
TrialSiteId: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
IsRoutineMRIPDEE: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsAuthorize: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
ISStrictManualBurnFlag: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsFollowStudyParameters: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
IsConfirmImagingTechnologist: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
],
|
||||
NotConfirmReson: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
NotFollowReson: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
NotStrictManualBurnFlagReason: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: 'blur' }
|
||||
],
|
||||
UserName: [
|
||||
{ required: true, validator: (rule, value, callback) => { !value ? callback(new Error(this.$t('trials:researchForm:formRule:specify'))) : callback() }, trigger: 'blur' },
|
||||
{ min: 0, max: 50, message: this.$t('trials:researchForm:formRule:maxLength'), trigger: ['blur', 'change'] }
|
||||
@@ -186,14 +295,173 @@ export default {
|
||||
state: null,
|
||||
userTypeEnumInt: zzSessionStorage.getItem('userTypeEnumInt') * 1,
|
||||
isShow: false,
|
||||
notShowFieldList: []
|
||||
notShowFieldList: [],
|
||||
perview_visible: false,
|
||||
ExternalList: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async beginScanFiles(e) {
|
||||
try {
|
||||
let file = e.target.files[0]
|
||||
let name = file.name
|
||||
if (!this.checkFileSuffix(name)) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:checkFileSuffix"))
|
||||
this.loading = true
|
||||
file = await this.fileToBlob(file)
|
||||
let scope = this
|
||||
var index = name.lastIndexOf('.')
|
||||
var type = name.substring(index + 1, name.length)
|
||||
let res = await this.OSSclient.put(
|
||||
`/${this.$route.query.trialId}/InspectionUpload/SiteSurvey/${this.form.TrialSiteId}/${scope.getGuid(Date.now() + '_' + name.split('.')[0])}.${type}`,
|
||||
file
|
||||
)
|
||||
let data = {
|
||||
Path: this.$getObjectName(res.url),
|
||||
FileName: name,
|
||||
FileSize: file.size,
|
||||
FileType: type
|
||||
|
||||
}
|
||||
res = await addOrUpdateCommonUploadRecord(data)
|
||||
this.loading = false
|
||||
if (res.IsSuccess) {
|
||||
this.form.CommonUploadRecordId = res.Result
|
||||
data.Id = res.Result
|
||||
this.form.SiteSurveyFile = data
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
checkFileSuffix(fileName) {
|
||||
var index = fileName.lastIndexOf('.')
|
||||
var suffix = fileName.substring(index + 1, fileName.length)
|
||||
if ('.pdf'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1 && '.docx'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1 && '.doc'.toLocaleLowerCase().search(suffix.toLocaleLowerCase()) === -1) {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
},
|
||||
handleIsAuthorizeInput(label) {
|
||||
this.form.IsAuthorizeRadiologistsParticipate = false
|
||||
this.form.AssignFixedTechnologists = false
|
||||
this.form[label] = true
|
||||
},
|
||||
async viewManualFile() {
|
||||
if (!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path) return this.$message.warning(this.$t("trials:researchForm:message:notFile"))
|
||||
this.$preview({
|
||||
path: this.form.SiteSurveyFile.Path,
|
||||
type: this.form.SiteSurveyFile.FileType,
|
||||
title: this.form.SiteSurveyFile.Path.FileName,
|
||||
})
|
||||
},
|
||||
async downLoad() {
|
||||
if (!this.form.SiteSurveyFile || !this.form.SiteSurveyFile.Path) return this.$message.warning(this.$t("trials:researchForm:message:notFile"))
|
||||
let link = document.createElement('a')
|
||||
link.href = this.OSSclientConfig.basePath + this.form.SiteSurveyFile.Path;
|
||||
link.target = '_blank'
|
||||
link.download = this.form.SiteSurveyFile.FileName
|
||||
link.style.display = 'none'
|
||||
document.body.append(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
link = null
|
||||
},
|
||||
async viewManual() {
|
||||
try {
|
||||
let data = {
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
TrialId: this.$route.query.trialId,
|
||||
IsPublish: true,
|
||||
FileTypeCode: 4,
|
||||
IsDeleted: false
|
||||
}
|
||||
let res = await getTrialDocumentList(data)
|
||||
if (res.IsSuccess) {
|
||||
const { CurrentPageData } = res.Result
|
||||
if (CurrentPageData.length <= 0) return this.$message.warning(this.$t("trials:researchRecord:ImageManual:message:noImageManual"))
|
||||
this.ExternalList = []
|
||||
CurrentPageData.forEach(item => {
|
||||
let obj = {
|
||||
FilePath: item.Path,
|
||||
FileFormat: 'pdf',
|
||||
Name: item.Name
|
||||
}
|
||||
this.ExternalList.push(obj)
|
||||
});
|
||||
// this.perview_visible = true
|
||||
this.ExternalList.forEach(item => {
|
||||
let link = document.createElement('a')
|
||||
link.href = this.OSSclientConfig.basePath + item.FilePath;
|
||||
link.target = '_blank'
|
||||
link.download = item.Name
|
||||
link.style.display = 'none'
|
||||
document.body.append(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
link = null
|
||||
})
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
// 保存基本信息
|
||||
handleSave(isAutoCommit) {
|
||||
return new Promise(async(resolve) => {
|
||||
handleSave(isAutoCommit, isCheck = false) {
|
||||
return new Promise(async (resolve) => {
|
||||
isCheck = false
|
||||
try {
|
||||
if (this.IsOnlyUploadFile && !isCheck) {
|
||||
if (!this.form.UserName) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notUserName"))
|
||||
return resolve(false)
|
||||
}
|
||||
if (!this.form.Phone) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notPhone"))
|
||||
return resolve(false)
|
||||
}
|
||||
if (!this.form.CommonUploadRecordId) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notCommonUploadRecordId"))
|
||||
return resolve(false)
|
||||
}
|
||||
this.btnLoading = true
|
||||
const param = {
|
||||
id: this.form.Id,
|
||||
trialId: this.$route.query.trialId,
|
||||
trialSiteId: this.form.TrialSiteId,
|
||||
userName: this.form.UserName,
|
||||
phone: this.form.Phone,
|
||||
email: this.form.Email,
|
||||
averageEngravingCycle: this.form.AverageEngravingCycle,
|
||||
IsRoutineMRIPDEE: this.form.IsRoutineMRIPDEE,
|
||||
MRIPDFFScanTime: this.form.MRIPDFFScanTime,
|
||||
MRIPDFFLeadTime: this.form.MRIPDFFLeadTime,
|
||||
MRIPDFFOther: this.form.MRIPDFFOther,
|
||||
IsAuthorizeRadiologistsParticipate: this.form.IsAuthorizeRadiologistsParticipate,
|
||||
AssignFixedTechnologists: this.form.AssignFixedTechnologists,
|
||||
ISStrictManualBurnFlag: this.form.ISStrictManualBurnFlag,
|
||||
NotStrictManualBurnFlagReason: this.form.NotStrictManualBurnFlagReason,
|
||||
isConfirmImagingTechnologist: this.form.IsConfirmImagingTechnologist,
|
||||
notConfirmReson: this.form.NotConfirmReson,
|
||||
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
||||
isFollowStudyParameters: this.form.IsFollowStudyParameters,
|
||||
notFollowReson: this.form.NotFollowReson,
|
||||
CommonUploadRecordId: this.form.CommonUploadRecordId
|
||||
}
|
||||
addOrUpdateTrialSiteSurvey(param).then(res => {
|
||||
this.btnLoading = false
|
||||
if (res.IsSuccess && !isAutoCommit) {
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
}
|
||||
resolve(true)
|
||||
}).catch(() => {
|
||||
this.btnLoading = false
|
||||
reject(false)
|
||||
})
|
||||
return resolve(true)
|
||||
}
|
||||
const valid = await this.$refs['researchBSForm'].validate()
|
||||
if (valid) {
|
||||
this.loading = true
|
||||
@@ -205,11 +473,20 @@ export default {
|
||||
phone: this.form.Phone,
|
||||
email: this.form.Email,
|
||||
averageEngravingCycle: this.form.AverageEngravingCycle,
|
||||
IsRoutineMRIPDEE: this.form.IsRoutineMRIPDEE,
|
||||
MRIPDFFScanTime: this.form.MRIPDFFScanTime,
|
||||
MRIPDFFLeadTime: this.form.MRIPDFFLeadTime,
|
||||
MRIPDFFOther: this.form.MRIPDFFOther,
|
||||
IsAuthorizeRadiologistsParticipate: this.form.IsAuthorizeRadiologistsParticipate,
|
||||
AssignFixedTechnologists: this.form.AssignFixedTechnologists,
|
||||
ISStrictManualBurnFlag: this.form.ISStrictManualBurnFlag,
|
||||
NotStrictManualBurnFlagReason: this.form.NotStrictManualBurnFlagReason,
|
||||
isConfirmImagingTechnologist: this.form.IsConfirmImagingTechnologist,
|
||||
notConfirmReson: this.form.NotConfirmReson,
|
||||
efficacyEvaluatorType: this.form.EfficacyEvaluatorType,
|
||||
isFollowStudyParameters: this.form.IsFollowStudyParameters,
|
||||
notFollowReson: this.form.NotFollowReson
|
||||
notFollowReson: this.form.NotFollowReson,
|
||||
CommonUploadRecordId: this.form.CommonUploadRecordId
|
||||
}
|
||||
const res = await addOrUpdateTrialSiteSurvey(param)
|
||||
this.loading = false
|
||||
@@ -232,7 +509,7 @@ export default {
|
||||
// 初始化
|
||||
async initForm(trialInfo, trialSiteSurvey, notShowFieldList) {
|
||||
// 获取项目下的site
|
||||
const { Result } = await getTrialSiteSelect(this.$route.query.trialId)
|
||||
const { Result } = await getTrialSiteSelect(this.$route.query.trialId, { IgnoreDisable: true })
|
||||
this.siteOptions = Result
|
||||
this.form.Id = trialSiteSurvey.Id
|
||||
this.form.Sponsor = trialInfo.Sponsor // 申办方
|
||||
@@ -246,7 +523,20 @@ export default {
|
||||
this.form.UserName = trialSiteSurvey.UserName // 联系人
|
||||
this.form.Phone = trialSiteSurvey.Phone // 联系人电话
|
||||
this.form.Email = trialSiteSurvey.Email // 联系人邮箱
|
||||
this.form.CommonUploadRecordId = trialSiteSurvey.CommonUploadRecordId
|
||||
this.form.SiteSurveyFile = trialSiteSurvey.SiteSurveyFile || {}
|
||||
this.form.fileStr = this.form.SiteSurveyFile.FileName
|
||||
this.form.AverageEngravingCycle = trialSiteSurvey.AverageEngravingCycle
|
||||
this.form.IsRoutineMRIPDEE = trialSiteSurvey.IsRoutineMRIPDEE
|
||||
this.form.MRIPDFFScanTime = trialSiteSurvey.MRIPDFFScanTime
|
||||
this.form.MRIPDFFLeadTime = trialSiteSurvey.MRIPDFFLeadTime
|
||||
this.form.MRIPDFFOther = trialSiteSurvey.MRIPDFFOther
|
||||
this.form.IsAuthorizeRadiologistsParticipate = trialSiteSurvey.IsAuthorizeRadiologistsParticipate
|
||||
this.form.AssignFixedTechnologists = trialSiteSurvey.AssignFixedTechnologists
|
||||
if (this.form.IsAuthorizeRadiologistsParticipate) this.form.IsAuthorize = 'IsAuthorizeRadiologistsParticipate'
|
||||
if (this.form.AssignFixedTechnologists) this.form.IsAuthorize = 'AssignFixedTechnologists'
|
||||
this.form.ISStrictManualBurnFlag = trialSiteSurvey.ISStrictManualBurnFlag
|
||||
this.form.NotStrictManualBurnFlagReason = trialSiteSurvey.NotStrictManualBurnFlagReason
|
||||
this.form.IsConfirmImagingTechnologist = trialSiteSurvey.IsConfirmImagingTechnologist
|
||||
this.form.NotConfirmReson = trialSiteSurvey.NotConfirmReson
|
||||
this.form.EfficacyEvaluatorType = trialSiteSurvey.EfficacyEvaluatorType
|
||||
@@ -267,39 +557,46 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.research_bs_content{
|
||||
.research_bs_content {
|
||||
|
||||
.basic_content{
|
||||
.basic_content {
|
||||
padding: 0 20px;
|
||||
background: #fff;
|
||||
|
||||
}
|
||||
.login_content{
|
||||
|
||||
.login_content {
|
||||
padding: 5px 20px;
|
||||
margin-top: 5px;
|
||||
background: #fff;
|
||||
|
||||
::v-deep .el-form-item {
|
||||
padding-bottom: 20px;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
.code_content{
|
||||
display:flex;
|
||||
|
||||
.code_content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
.el-input{
|
||||
|
||||
.el-input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.form-label-width{
|
||||
::v-deep .el-form-item__label{
|
||||
|
||||
.form-label-width {
|
||||
::v-deep .el-form-item__label {
|
||||
width: 140px;
|
||||
}
|
||||
::v-deep .el-form-item__content{
|
||||
|
||||
::v-deep .el-form-item__content {
|
||||
margin-left: 140px;
|
||||
}
|
||||
}
|
||||
.submit_content{
|
||||
|
||||
.submit_content {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -308,10 +605,61 @@ export default {
|
||||
margin-bottom: 0px;
|
||||
padding-top: 5px;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
.el-form-item__content{
|
||||
|
||||
.el-form-item__content {
|
||||
color: #82848a;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.upload {
|
||||
display: inline-block;
|
||||
height: 36px;
|
||||
width: 90px;
|
||||
padding: 0 10px;
|
||||
line-height: 23px;
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
text-align: center;
|
||||
background: #428bca;
|
||||
border-color: #428bca;
|
||||
color: #fff;
|
||||
margin-right: 5px;
|
||||
|
||||
.select-file {
|
||||
height: 36px;
|
||||
width: 90px;
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
left: 0;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.btn-select {
|
||||
//给显示在页面上的按钮写样式
|
||||
// width: 70px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 24px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 10px;
|
||||
pointer-events: none; //pointer-events:none用来控制该标签的点击穿透事件
|
||||
}
|
||||
}
|
||||
|
||||
.file {
|
||||
::v-deep .el-form-item__content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,59 +1,107 @@
|
||||
<template>
|
||||
<div
|
||||
v-loading="loading"
|
||||
class="equipment_form_content"
|
||||
>
|
||||
<el-form
|
||||
ref="equipmentForm"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
label-position="left"
|
||||
>
|
||||
<div v-loading="loading" class="equipment_form_content">
|
||||
<el-form ref="equipmentForm" :model="form" :rules="rules" label-position="left">
|
||||
<!-- 扫描设备 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeId">
|
||||
<el-select
|
||||
v-model="form.EquipmentTypeId"
|
||||
style="width:100%"
|
||||
>
|
||||
<el-option
|
||||
v-for="item of $d.SiteSurvey_ScanEquipmentType"
|
||||
:key="item.id"
|
||||
:label="item.label"
|
||||
:value="item.id"
|
||||
/>
|
||||
</el-select>
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:equipment')" prop="EquipmentTypeEnum"
|
||||
v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.EquipmentTypeEnum" style="width:100%" @change="form.OtherEquipmentType = null">
|
||||
<el-option v-for="item of $d.SiteSurvey_ScanEquipmentType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.OtherEquipmentType" style="margin-left: 10px;"
|
||||
v-if="form.EquipmentTypeEnum == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 扫描参数 -->
|
||||
<el-form-item v-if="isShowParameters" :label="$t('trials:equiptResearch:form:param')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:param')"
|
||||
v-if="EquipmentControlFieldList.includes('Parameters')" prop="Parameters">
|
||||
<el-input v-model="form.Parameters" />
|
||||
</el-form-item>
|
||||
<!-- 扫描仪器制造商名称 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')">
|
||||
<el-input v-model="form.ManufacturerName" />
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:manufacturer')"
|
||||
v-if="EquipmentControlFieldList.includes('ManufacturerType')" prop="ManufacturerType">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.ManufacturerType" style="width:100%" @change="form.ManufacturerName = null">
|
||||
<el-option v-for="item of $d.ManufacturerType" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.ManufacturerName" style="margin-left: 10px;"
|
||||
v-if="form.ManufacturerType == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 扫描仪型号 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:model')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:model')"
|
||||
v-if="EquipmentControlFieldList.includes('ScannerType')" prop="ScannerType">
|
||||
<el-input v-model="form.ScannerType" />
|
||||
</el-form-item>
|
||||
<!-- 磁场强度 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:MagneticFieldStrengthType')"
|
||||
v-if="EquipmentControlFieldList.includes('MagneticFieldStrengthType')" prop="MagneticFieldStrengthType">
|
||||
<el-select v-model="form.MagneticFieldStrengthType" style="width:100%">
|
||||
<el-option v-for="item of $d.MagneticFieldStrengthType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 体部线圈通道数 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:BodyCoilChannelCount')"
|
||||
v-if="EquipmentControlFieldList.includes('BodyCoilChannelCount')" prop="BodyCoilChannelCount">
|
||||
<el-select v-model="form.BodyCoilChannelCount" style="width:100%">
|
||||
<el-option v-for="item of $d.BodyCoilChannelCount" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 是否具备专用的PDFF脂肪定量序列(CSE-MRI序列) -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:HasDedicatedPdfFatQuantificationSequence')"
|
||||
v-if="EquipmentControlFieldList.includes('HasDedicatedPdfFatQuantificationSequence')"
|
||||
prop="HasDedicatedPdfFatQuantificationSequence">
|
||||
<el-select v-model="form.HasDedicatedPdfFatQuantificationSequence" style="width:100%"
|
||||
@change="form.PdfFatQuantificationSequenceType = null, form.OtherSequenceSpecification = null">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- PDFF脂肪定量序列 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:PdfFatQuantificationSequenceType')"
|
||||
prop="PdfFatQuantificationSequenceType"
|
||||
v-if="form.HasDedicatedPdfFatQuantificationSequence && EquipmentControlFieldList.includes('PdfFatQuantificationSequenceType')">
|
||||
<div style="display: flex;align-items: center;">
|
||||
<el-select v-model="form.PdfFatQuantificationSequenceType" style="width:100%"
|
||||
@change="form.OtherSequenceSpecification = null">
|
||||
<el-option v-for="item of $d.PdfFatQuantificationSequenceType" :key="item.id" :label="item.label"
|
||||
:value="item.value" />
|
||||
</el-select>
|
||||
<el-input placeholder="" v-model="form.OtherSequenceSpecification" style="margin-left: 10px;"
|
||||
v-if="form.PdfFatQuantificationSequenceType == '-1'" clearable>
|
||||
</el-input>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<!-- 是否包含 T2/R2 校正(用于铁沉积校正) -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:HasT2R2Correction')" prop="HasT2R2Correction"
|
||||
v-if="EquipmentControlFieldList.includes('HasT2R2Correction')">
|
||||
<el-select v-model="form.HasT2R2Correction" style="width:100%">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 是否可完整导出 PDFF 参数图及全部原始 DICOM 数据 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:CanFullyExportPdfParameterMapsAndRawDicom')"
|
||||
prop="CanFullyExportPdfParameterMapsAndRawDicom"
|
||||
v-if="EquipmentControlFieldList.includes('CanFullyExportPdfParameterMapsAndRawDicom')">
|
||||
<el-select v-model="form.CanFullyExportPdfParameterMapsAndRawDicom" style="width:100%">
|
||||
<el-option v-for="item of $d.YesOrNo" :key="item.id" :label="item.label" :value="item.value" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 备注 -->
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:remark')">
|
||||
<el-form-item :label="$t('trials:equiptResearch:form:remark')" prop="Note"
|
||||
v-if="EquipmentControlFieldList.includes('Note')">
|
||||
<el-input v-model="form.Note" />
|
||||
</el-form-item>
|
||||
<div style="text-align: center;padding:20px 0px;">
|
||||
<!-- 取消 -->
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
@click="handleCancel"
|
||||
>
|
||||
<el-button size="large" type="primary" @click="handleCancel">
|
||||
{{ $t("common:button:cancel") }}
|
||||
</el-button>
|
||||
<!-- 保存 -->
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
@click="handleSave"
|
||||
>
|
||||
<el-button size="large" type="primary" @click="handleSave">
|
||||
{{ $t("common:button:save") }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -76,29 +124,96 @@ export default {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
isShowParameters: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
EquipmentControlFieldList: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return []
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
form: {
|
||||
Id: '',
|
||||
EquipmentTypeId: '',
|
||||
Parameters: '',
|
||||
ManufacturerName: '',
|
||||
ScannerType: '',
|
||||
Note: '',
|
||||
EquipmentTypeEnum: null,
|
||||
OtherEquipmentType: null,
|
||||
Parameters: null,
|
||||
Note: null,
|
||||
ManufacturerType: null,
|
||||
ManufacturerName: null,
|
||||
ScannerType: null,
|
||||
MagneticFieldStrengthType: null,
|
||||
BodyCoilChannelCount: null,
|
||||
HasDedicatedPdfFatQuantificationSequence: null,
|
||||
PdfFatQuantificationSequenceType: null,
|
||||
OtherSequenceSpecification: null,
|
||||
HasT2R2Correction: null,
|
||||
CanFullyExportPdfParameterMapsAndRawDicom: null,
|
||||
TrialSiteSurveyId: ''
|
||||
},
|
||||
rules: {
|
||||
EquipmentTypeId: [
|
||||
EquipmentTypeEnum: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.EquipmentTypeEnum === -1 && !this.form.OtherEquipmentType) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
Parameters: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
// Note: [
|
||||
// { required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
// ],
|
||||
ManufacturerType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.ManufacturerType === -1 && !this.form.ManufacturerName) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
ScannerType: [
|
||||
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
MagneticFieldStrengthType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
]
|
||||
],
|
||||
BodyCoilChannelCount: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
HasDedicatedPdfFatQuantificationSequence: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
PdfFatQuantificationSequenceType: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] },
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (this.form.PdfFatQuantificationSequenceType === -1 && !this.form.OtherSequenceSpecification) {
|
||||
callback(this.$t('common:ruleMessage:specify'));
|
||||
} else {
|
||||
callback()
|
||||
}
|
||||
}, message: this.$t('common:ruleMessage:specify'), trigger: ['blur', 'change']
|
||||
},
|
||||
],
|
||||
HasT2R2Correction: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
CanFullyExportPdfParameterMapsAndRawDicom: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:select'), trigger: ['blur', 'change'] }
|
||||
],
|
||||
},
|
||||
loading: false,
|
||||
dictionaryList: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -154,13 +269,15 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.equipment_form_content{
|
||||
.equipment_form_content {
|
||||
padding: 0 10px;
|
||||
|
||||
::v-deep .el-form-item {
|
||||
margin-bottom: 0px;
|
||||
padding: 5px 0 20px 0;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
.el-form-item__content{
|
||||
|
||||
.el-form-item__content {
|
||||
color: #82848a;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,18 +13,22 @@
|
||||
<i class="el-icon-receiving" />
|
||||
</div>
|
||||
<div class="p_info">
|
||||
<div
|
||||
class="p_info_basic"
|
||||
:style="{maxWidth:w+'px','white-space': 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis'}"
|
||||
>
|
||||
<div class="p_text">{{ item.EquipmentType }}</div>
|
||||
<div v-if="isShowParameters" class="p_text" style="margin-left:10px">{{ item.Parameters }}</div>
|
||||
<div class="p_text" style="margin-left:10px">{{ item.ManufacturerName }}</div>
|
||||
<div class="p_info_basic" :style="{
|
||||
maxWidth: w + 'px', 'white-space': 'nowrap',
|
||||
overflow: 'hidden',
|
||||
'text-overflow': 'ellipsis'
|
||||
}">
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('EquipmentTypeEnum')">
|
||||
{{ item.OtherEquipmentType ? item.OtherEquipmentType :
|
||||
$fd('SiteSurvey_ScanEquipmentType', item.EquipmentTypeEnum) }}</div>
|
||||
<div v-if="EquipmentControlFieldList.includes('Parameters')" class="p_text" style="margin-left:10px">{{
|
||||
item.Parameters }}</div>
|
||||
<div class="p_text" style="margin-left:10px" v-if="EquipmentControlFieldList.includes('ManufacturerType')">{{
|
||||
item.ManufacturerName ? item.ManufacturerName : $fd('ManufacturerType',
|
||||
item.ManufacturerType) }}</div>
|
||||
</div>
|
||||
<div class="p_text">{{ item.ScannerType }}</div>
|
||||
<div class="p_text">{{ item.Note }}</div>
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('ScannerType')">{{ item.ScannerType }}</div>
|
||||
<div class="p_text" v-if="EquipmentControlFieldList.includes('Note')">{{ item.Note }}</div>
|
||||
</div>
|
||||
<div v-if="state === 0 && userTypeEnumInt === 0 && !isHistory" class="p_func">
|
||||
<el-button type="text" @click="handleEdit(item)">
|
||||
@@ -36,19 +40,9 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- 添加/编辑设备信息 -->
|
||||
<el-drawer
|
||||
:title="title"
|
||||
:visible.sync="formVisible"
|
||||
direction="btt"
|
||||
size="70%"
|
||||
>
|
||||
<EquipmentForm
|
||||
v-if="formVisible"
|
||||
:equipment-info="equipmentInfo"
|
||||
:is-show-parameters="isShowParameters"
|
||||
@getList="getList"
|
||||
@close="close"
|
||||
/>
|
||||
<el-drawer :title="title" :visible.sync="formVisible" direction="btt" size="70%">
|
||||
<EquipmentForm v-if="formVisible" :equipment-info="equipmentInfo"
|
||||
:EquipmentControlFieldList="EquipmentControlFieldList" @getList="getList" @close="close" />
|
||||
</el-drawer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -81,7 +75,7 @@ export default {
|
||||
state: null,
|
||||
trialSiteSurveyId: '',
|
||||
trialId: '',
|
||||
isShowParameters: false
|
||||
EquipmentControlFieldList: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -142,8 +136,11 @@ export default {
|
||||
console.log(e)
|
||||
}
|
||||
},
|
||||
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, isShowParameters) {
|
||||
this.isShowParameters = isShowParameters
|
||||
initList(TrialSiteEquipmentSurveyList, trialSiteSurvey, EquipmentControlFieldList) {
|
||||
this.EquipmentControlFieldList = []
|
||||
EquipmentControlFieldList.forEach(item => {
|
||||
this.EquipmentControlFieldList.push(item.FiledName)
|
||||
})
|
||||
this.list = TrialSiteEquipmentSurveyList
|
||||
this.state = trialSiteSurvey.State
|
||||
this.$forceUpdate()
|
||||
@@ -157,63 +154,70 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.equipments_content{
|
||||
.equipments_content {
|
||||
background: #fff;
|
||||
padding: 10px;
|
||||
.title{
|
||||
|
||||
.title {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.equipment_info{
|
||||
|
||||
.equipment_info {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
border-top: 1px solid #f5f7fa;
|
||||
.p_icon{
|
||||
|
||||
.p_icon {
|
||||
width: 70px;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
.p_info{
|
||||
|
||||
.p_info {
|
||||
position: relative;
|
||||
flex:1;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-evenly;
|
||||
// border-right: 1px solid #f5f7fa;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.p_info:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
height: 50px;
|
||||
width: 1px;
|
||||
background-color: #f5f7fa;
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
right: 0;
|
||||
height: 50px;
|
||||
width: 1px;
|
||||
background-color: #f5f7fa;
|
||||
}
|
||||
.p_info_basic{
|
||||
|
||||
.p_info_basic {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
.p_text{
|
||||
|
||||
.p_text {
|
||||
line-height: 25px;
|
||||
color: #82848a;
|
||||
}
|
||||
.p_func{
|
||||
|
||||
.p_func {
|
||||
width: 80px;
|
||||
padding: 0 10px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -4,30 +4,22 @@
|
||||
<div class="d_content">
|
||||
|
||||
<!-- 项目基本信息 -->
|
||||
<BasicInfo ref="basicInfo" />
|
||||
<BasicInfo ref="basicInfo" :IsOnlyUploadFile="IsOnlyUploadFile" :IsSupportUploadFile="IsSupportUploadFile" />
|
||||
<!-- 历史人员 -->
|
||||
<HistoricalParticipants ref="historicalParticipant" class="mt5" />
|
||||
<!-- 新增人员 -->
|
||||
<Participants ref="participants" class="mt5" />
|
||||
<!-- 设备调研 -->
|
||||
<Equipments ref="equipments" class="mt5" />
|
||||
<Equipments ref="equipments" class="mt5" v-if="!siteSurveyNoteInfo.IsCloseEquipmentSurvey" />
|
||||
<!-- 备注 -->
|
||||
<Notes ref="notes" class="mt5" />
|
||||
</div>
|
||||
<div class="d_footer">
|
||||
<div class="d_func_row">
|
||||
<div
|
||||
v-if="state === 0 && userTypeEnumInt === 0"
|
||||
class="d_func"
|
||||
@click="handleSave"
|
||||
>
|
||||
<div v-if="state === 0 && userTypeEnumInt === 0" class="d_func" @click="handleSave">
|
||||
{{ $t('common:button:save') }}
|
||||
</div>
|
||||
<div
|
||||
v-if="(state === 0 && userTypeEnumInt === 0)"
|
||||
class="d_func"
|
||||
@click="handleSubmit('submit')"
|
||||
>
|
||||
<div v-if="(state === 0 && userTypeEnumInt === 0)" class="d_func" @click="handleSubmit('submit')">
|
||||
{{ $t('trials:researchForm:button:submit') }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -58,7 +50,9 @@ export default {
|
||||
userTypeEnumInt: 0,
|
||||
rejectVisible: false,
|
||||
rejectForm: { reason: '' },
|
||||
siteSurveyNoteInfo: null
|
||||
siteSurveyNoteInfo: {},
|
||||
IsSupportUploadFile: false,
|
||||
IsOnlyUploadFile: false
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -78,6 +72,9 @@ export default {
|
||||
if (res.Result.SiteSurveyFiledConfig && res.Result.SiteSurveyFiledConfig.ModifyFiledList.length > 0) {
|
||||
this.siteSurveyNoteInfo = res.Result.SiteSurveyFiledConfig.ModifyFiledList.find(i => i.NeedModifyFiled === 'SiteSurveyNote')
|
||||
}
|
||||
this.IsSupportUploadFile = res.Result.SiteSurveyFiledConfig.IsSupportUploadFile
|
||||
this.IsOnlyUploadFile = res.Result.SiteSurveyFiledConfig.IsOnlyUploadFile
|
||||
this.siteSurveyNoteInfo.IsCloseEquipmentSurvey = res.Result.SiteSurveyFiledConfig.IsCloseEquipmentSurvey
|
||||
this.state = res.Result.TrialSiteSurvey.State
|
||||
this.$refs['basicInfo'].initForm(res.Result.TrialInfo, res.Result.TrialSiteSurvey, res.Result.SiteSurveyFiledConfig ? res.Result.SiteSurveyFiledConfig.NotShowFieldList : null)
|
||||
var historicalArr = []
|
||||
@@ -92,7 +89,7 @@ export default {
|
||||
|
||||
this.$refs['historicalParticipant'].initList(historicalArr, res.Result.TrialSiteSurvey)
|
||||
this.$refs['participants'].initList(newArr, res.Result.TrialSiteSurvey)
|
||||
this.$refs['equipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, !(res.Result.SiteSurveyFiledConfig && res.Result.SiteSurveyFiledConfig.ModifyFiledList.length > 0))
|
||||
this.$refs['equipments'].initList(res.Result.TrialSiteEquipmentSurveyList, res.Result.TrialSiteSurvey, res.Result.SiteSurveyFiledConfig.EquipmentControlFieldList)
|
||||
this.$refs['notes'].initPage(this.siteSurveyNoteInfo)
|
||||
}
|
||||
this.loading = false
|
||||
@@ -129,7 +126,8 @@ export default {
|
||||
this.userTypeEnumInt === 0 ? this.$t('trials:researchForm:message:submitWarning') : this.$t('trials:researchForm:message:submitWarning2'),
|
||||
{
|
||||
type: 'warning',
|
||||
distinguishCancelAndClose: true
|
||||
distinguishCancelAndClose: true,
|
||||
customClass: "mobile_confirm"
|
||||
}
|
||||
)
|
||||
if (confirm !== 'confirm') return
|
||||
@@ -160,9 +158,10 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.research_detal_wrapper{
|
||||
background-color:#f5f7fa;
|
||||
.d_title{
|
||||
.research_detal_wrapper {
|
||||
background-color: #f5f7fa;
|
||||
|
||||
.d_title {
|
||||
margin-bottom: 5px;
|
||||
line-height: 80px;
|
||||
font-size: 28px;
|
||||
@@ -173,10 +172,11 @@ export default {
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
// .d_content{
|
||||
|
||||
// }
|
||||
.d_footer{
|
||||
.d_footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
@@ -185,12 +185,14 @@ export default {
|
||||
text-align: center;
|
||||
// padding: 20px;
|
||||
}
|
||||
.d_func_row{
|
||||
|
||||
.d_func_row {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.d_func{
|
||||
|
||||
.d_func {
|
||||
flex: 1;
|
||||
margin: 20px;
|
||||
color: #fff;
|
||||
@@ -207,15 +209,16 @@ export default {
|
||||
line-height: 1;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
&:hover{
|
||||
|
||||
&:hover {
|
||||
background: #68a2d5;
|
||||
border-color: #68a2d5;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.mt5{
|
||||
|
||||
.mt5 {
|
||||
margin-top: 5px
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
+240
-140
@@ -1,131 +1,88 @@
|
||||
<template>
|
||||
<div class="research_login_m_content">
|
||||
<div class="title">{{ $t('trials:researchForm:title:question') }}</div>
|
||||
<el-form
|
||||
ref="loginForm"
|
||||
v-loading="loading"
|
||||
label-position="left"
|
||||
label-width="120px"
|
||||
:model="form"
|
||||
:rules="rules"
|
||||
>
|
||||
<div class="basic_content">
|
||||
<!-- 项目编号 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:trialId')"
|
||||
>
|
||||
<span>{{ form.TrialCode }}</span>
|
||||
</el-form-item>
|
||||
<!-- 试验方案号 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:researchNo')"
|
||||
>
|
||||
<span>{{ form.ResearchProgramNo }}</span>
|
||||
</el-form-item>
|
||||
<!-- 试验名称 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:researchName')"
|
||||
>
|
||||
<span>{{ form.ExperimentName }}</span>
|
||||
</el-form-item>
|
||||
<!-- 适应症类型 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:decleareType')"
|
||||
>
|
||||
<span>{{ form.IndicationType }}</span>
|
||||
</el-form-item>
|
||||
<div v-if="IsExpired"></div>
|
||||
<div v-else-if="verify" class="LinkVerificationCode_content">
|
||||
<el-form ref="codeForm" v-loading="loading" label-position="top" label-width="120px" :model="codeForm"
|
||||
:rules="code_rules">
|
||||
<div class="basic_content">
|
||||
<!-- 项目编号 -->
|
||||
<el-form-item :label="$t('trials:researchForm:message:LinkVerificationCode')" prop="LinkVerificationCode">
|
||||
<el-input v-model="codeForm.LinkVerificationCode" autocomplete="new-password" />
|
||||
</el-form-item>
|
||||
</div>
|
||||
</el-form>
|
||||
<div class="submit_content">
|
||||
<el-button size="large" type="primary" @click="getLinkVerificationCodeIsEffective">
|
||||
{{ $t('common:button:submit') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="login_content">
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:siteName')"
|
||||
prop="TrialSiteId"
|
||||
>
|
||||
<el-select
|
||||
v-model="form.TrialSiteId"
|
||||
filterable
|
||||
style="width:100%;"
|
||||
@change="handleSiteChange"
|
||||
>
|
||||
<el-option
|
||||
v-for="(item,index) of siteOptions"
|
||||
:key="index"
|
||||
:label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="form.TrialSiteId && isHaveSiteSurveyRecord"
|
||||
label=""
|
||||
style="text-align:right;"
|
||||
>
|
||||
<!-- 更新调研表 -->
|
||||
<el-link
|
||||
v-if="!form.IsUpdate"
|
||||
type="primary"
|
||||
@click="form.IsUpdate = true"
|
||||
>
|
||||
{{ $t('trials:researchForm:button:updateQsForm') }}
|
||||
</el-link>
|
||||
<!-- 取消更新调研表 -->
|
||||
<el-link
|
||||
v-else
|
||||
type="primary"
|
||||
@click="form.IsUpdate = false;form.ReplaceUserEmailOrPhone=''"
|
||||
>
|
||||
{{ $t('trials:researchForm:button:cancelUpdateQsForm') }}
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<template v-else>
|
||||
<div class="title">{{ $t('trials:researchForm:title:question') }}</div>
|
||||
<el-form ref="loginForm" v-loading="loading" label-position="left" label-width="120px" :model="form"
|
||||
:rules="rules">
|
||||
<div class="basic_content">
|
||||
<!-- 项目编号 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:trialId')">
|
||||
<span>{{ form.TrialCode }}</span>
|
||||
</el-form-item>
|
||||
<!-- 试验方案号 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:researchNo')">
|
||||
<span>{{ form.ResearchProgramNo }}</span>
|
||||
</el-form-item>
|
||||
<!-- 试验名称 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:researchName')">
|
||||
<span>{{ form.ExperimentName }}</span>
|
||||
</el-form-item>
|
||||
<!-- 适应症类型 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:decleareType')">
|
||||
<span>{{ form.IndicationType }}</span>
|
||||
</el-form-item>
|
||||
</div>
|
||||
<div class="login_content">
|
||||
<el-form-item :label="$t('trials:researchForm:form:siteName')" prop="TrialSiteId">
|
||||
<el-select v-model="form.TrialSiteId" filterable style="width:100%;" @change="handleSiteChange">
|
||||
<el-option v-for="(item, index) of siteOptions" :key="index" :label="item.TrialSiteAliasName"
|
||||
:value="item.TrialSiteId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<el-form-item v-if="form.TrialSiteId && isHaveSiteSurveyRecord" label="" style="text-align:right;">
|
||||
<!-- 更新调研表 -->
|
||||
<el-link v-if="!form.IsUpdate" type="primary" @click="form.IsUpdate = true">
|
||||
{{ $t('trials:researchForm:button:updateQsForm') }}
|
||||
</el-link>
|
||||
<!-- 取消更新调研表 -->
|
||||
<el-link v-else type="primary" @click="form.IsUpdate = false; form.ReplaceUserEmailOrPhone = ''">
|
||||
{{ $t('trials:researchForm:button:cancelUpdateQsForm') }}
|
||||
</el-link>
|
||||
</el-form-item>
|
||||
|
||||
<!-- 原调研表填写人邮箱 -->
|
||||
<el-form-item
|
||||
v-if="form.IsUpdate"
|
||||
:label="$t('trials:researchForm:form:originalEmail')"
|
||||
prop="ReplaceUserEmailOrPhone"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.ReplaceUserEmailOrPhone"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- 联系邮箱 -->
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:contactorEmail')"
|
||||
prop="EmailOrPhone"
|
||||
>
|
||||
<el-input
|
||||
v-model="form.EmailOrPhone"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
:label="$t('trials:researchForm:form:verifyCode')"
|
||||
>
|
||||
<div class="code_content">
|
||||
<el-input
|
||||
v-model="form.VerificationCode"
|
||||
autocomplete="new-password"
|
||||
/>
|
||||
<el-button
|
||||
type="primary"
|
||||
:disabled="sendDisabled || !form.EmailOrPhone || count > 0"
|
||||
@click="handleSendCode"
|
||||
>
|
||||
{{ this.$t('trials:researchForm:button:send') }} {{ sendTitle ? `${sendTitle}` : null }}
|
||||
<!-- 原调研表填写人邮箱 -->
|
||||
<el-form-item v-if="form.IsUpdate" :label="$t('trials:researchForm:form:originalEmail')"
|
||||
prop="ReplaceUserEmailOrPhone">
|
||||
<el-input v-model="form.ReplaceUserEmailOrPhone" autocomplete="new-password" />
|
||||
</el-form-item>
|
||||
<!-- 联系邮箱 -->
|
||||
<el-form-item :label="$t('trials:researchForm:form:contactorEmail')" prop="EmailOrPhone">
|
||||
<el-input v-model="form.EmailOrPhone" autocomplete="new-password" />
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('trials:researchForm:form:verifyCode')">
|
||||
<div class="code_content">
|
||||
<el-input v-model="form.VerificationCode" autocomplete="new-password" />
|
||||
<el-button type="primary" :disabled="sendDisabled || !form.EmailOrPhone || count > 0"
|
||||
@click="handleSendCode">
|
||||
{{ this.$t('trials:researchForm:button:send') }} {{ sendTitle ? `${sendTitle}` : null }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<div class="submit_content">
|
||||
<el-button size="large" type="primary" @click="onSubmit">
|
||||
{{ $t('common:button:submit') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<div class="submit_content">
|
||||
<el-button
|
||||
size="large"
|
||||
type="primary"
|
||||
@click="onSubmit"
|
||||
>
|
||||
{{ $t('common:button:submit') }}
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</el-form>
|
||||
</el-form>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -133,6 +90,10 @@ import { sendVerifyCode, verifySendCode, getTrialSurveyInitInfo } from '@/api/re
|
||||
import { getUserMenuTree, getUserPermissions } from '@/api/user'
|
||||
import store from '@/store'
|
||||
import { mapGetters, mapMutations } from 'vuex'
|
||||
import {
|
||||
getLinkLinkExpirationTime,
|
||||
getLinkVerificationCodeIsEffective
|
||||
} from '@/api/trials'
|
||||
export default {
|
||||
name: 'ResearchMobileLogin',
|
||||
data() {
|
||||
@@ -185,6 +146,16 @@ export default {
|
||||
}
|
||||
return {
|
||||
trialId: '',
|
||||
IsExpired: true,
|
||||
verify: true,
|
||||
codeForm: {
|
||||
LinkVerificationCode: null,
|
||||
},
|
||||
code_rules: {
|
||||
LinkVerificationCode: [
|
||||
{ required: true, message: this.$t('trials:researchForm:formRule:specify'), trigger: ['blur'] }
|
||||
],
|
||||
},
|
||||
form: {
|
||||
Sponsor: null, // 申办方
|
||||
ResearchProgramNo: null, // 方案号
|
||||
@@ -239,16 +210,119 @@ export default {
|
||||
])
|
||||
},
|
||||
mounted() {
|
||||
this.$i18n.locale = this.$route.query.lang
|
||||
this.setLanguage(this.$route.query.lang)
|
||||
this.$updateDictionary()
|
||||
if (this.$route.query.trialId) {
|
||||
this.trialId = this.$route.query.trialId
|
||||
this.initPage()
|
||||
let lang = this.$route.query.lang
|
||||
if (!lang) {
|
||||
const language = navigator.language
|
||||
lang = 'en'
|
||||
if (language.includes("zh")) {
|
||||
lang = 'zh'
|
||||
}
|
||||
}
|
||||
this.$i18n.locale = lang
|
||||
this.setLanguage(lang)
|
||||
this.$updateDictionary()
|
||||
this.getLinkTimeIsExpired()
|
||||
},
|
||||
methods: {
|
||||
...mapMutations({ setLanguage: 'lang/setLanguage' }),
|
||||
async getLinkTimeIsExpired() {
|
||||
try {
|
||||
let data = {
|
||||
TrialId: this.$route.query.trialId,
|
||||
}
|
||||
let res = await getLinkLinkExpirationTime(data)
|
||||
if (res.IsSuccess) {
|
||||
if (res.Result.IsExpired) {
|
||||
return this.$router.replace('/link_expired')
|
||||
// return this.$confirm(this.$t("trials:researchForm:confirm:linkIsExpired"), '', {
|
||||
// type: 'warning'
|
||||
// })
|
||||
// return this.IsExpired = true
|
||||
}
|
||||
// this.customPrompt()
|
||||
this.IsExpired = false
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
async getLinkVerificationCodeIsEffective() {
|
||||
try {
|
||||
let validate = await this.$refs.codeForm.validate()
|
||||
if (!validate) return false
|
||||
let data = {
|
||||
TrialId: this.$route.query.trialId,
|
||||
LinkVerificationCode: this.codeForm.LinkVerificationCode
|
||||
}
|
||||
let res = await getLinkVerificationCodeIsEffective(data)
|
||||
if (res.IsSuccess) {
|
||||
if (!res.Result.IsEffective) {
|
||||
return false
|
||||
}
|
||||
this.verify = false
|
||||
if (this.$route.query.trialId) {
|
||||
this.trialId = this.$route.query.trialId
|
||||
this.initPage()
|
||||
}
|
||||
if (this.$route.query.isUpload) {
|
||||
this.isUpload = true
|
||||
this.form.IsUpdate = true
|
||||
let { email, oldEMail, trialSiteId } = this.$route.query
|
||||
if (trialSiteId) this.form.TrialSiteId = trialSiteId
|
||||
if (oldEMail) this.form.ReplaceUserEmailOrPhone = oldEMail
|
||||
if (email && email !== 'null') {
|
||||
this.form.EmailOrPhone = email
|
||||
} else {
|
||||
this.form.EmailOrPhone = oldEMail
|
||||
}
|
||||
if ((email && email !== 'null') || (oldEMail && oldEMail !== 'null')) {
|
||||
this.isNeedUpload = false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
} catch (err) {
|
||||
return false
|
||||
console.log(err)
|
||||
}
|
||||
},
|
||||
async customPrompt(name) {
|
||||
try {
|
||||
const that = this
|
||||
// 请输入标记名称
|
||||
let message = this.$t('trials:researchForm:message:LinkVerificationCode')
|
||||
const { value } = await this.$prompt(message, '', {
|
||||
showClose: false,
|
||||
cancelButtonText: this.$t('common:button:cancel'),
|
||||
confirmButtonText: this.$t('trials:researchForm:button:saveLinkCode'),
|
||||
showCancelButton: false,
|
||||
closeOnClickModal: false,
|
||||
closeOnPressEscape: false,
|
||||
inputValue: name,
|
||||
beforeClose: async (action, instance, done) => {
|
||||
if (action === 'confirm') {
|
||||
const value = instance.inputValue
|
||||
if (!value) {
|
||||
that.$message.error(this.$t('trials:researchForm:error:noValue'))
|
||||
} else {
|
||||
let flag = await this.getLinkVerificationCodeIsEffective(value)
|
||||
if (!flag) {
|
||||
that.$message.error(this.$t('trials:researchForm:confirm:isEffective'))
|
||||
} else {
|
||||
done()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
done()
|
||||
}
|
||||
}
|
||||
})
|
||||
this.getLinkVerificationCodeIsEffective(value)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return null
|
||||
}
|
||||
},
|
||||
// 初始化页面
|
||||
async initPage() {
|
||||
try {
|
||||
@@ -292,8 +366,18 @@ export default {
|
||||
|
||||
if (res.IsSuccess) {
|
||||
zzSessionStorage.clear()
|
||||
this.$i18n.locale = this.$route.query.lang
|
||||
this.setLanguage(this.$route.query.lang)
|
||||
// this.$i18n.locale = this.$route.query.lang
|
||||
// this.setLanguage(this.$route.query.lang)
|
||||
let lang = this.$route.query.lang
|
||||
if (!lang) {
|
||||
const language = navigator.language
|
||||
lang = 'en'
|
||||
if (language.includes("zh")) {
|
||||
lang = 'zh'
|
||||
}
|
||||
}
|
||||
this.$i18n.locale = lang
|
||||
this.setLanguage(lang)
|
||||
store.dispatch('user/setToken', res.Result.Token)
|
||||
zzSessionStorage.setItem('TokenKey', res.Result.Token)
|
||||
var permissions = await getUserPermissions()
|
||||
@@ -363,9 +447,10 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.research_login_m_content{
|
||||
background-color:#f5f7fa;
|
||||
.title{
|
||||
.research_login_m_content {
|
||||
background-color: #f5f7fa;
|
||||
|
||||
.title {
|
||||
margin-bottom: 5px;
|
||||
line-height: 80px;
|
||||
font-size: 28px;
|
||||
@@ -373,27 +458,33 @@ export default {
|
||||
text-align: center;
|
||||
background: #fff;
|
||||
}
|
||||
.basic_content{
|
||||
|
||||
.basic_content {
|
||||
padding: 0 20px;
|
||||
background: #fff;
|
||||
}
|
||||
.login_content{
|
||||
|
||||
.login_content {
|
||||
padding: 5px 20px;
|
||||
margin-top: 5px;
|
||||
background: #fff;
|
||||
|
||||
::v-deep .el-form-item {
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
}
|
||||
.code_content{
|
||||
display:flex;
|
||||
|
||||
.code_content {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
.el-input{
|
||||
|
||||
.el-input {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.submit_content{
|
||||
|
||||
.submit_content {
|
||||
margin-top: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
@@ -402,11 +493,20 @@ export default {
|
||||
margin-bottom: 0px;
|
||||
padding-top: 5px;
|
||||
border-bottom: 1px solid #f5f7fa;
|
||||
.el-form-item__content{
|
||||
|
||||
.el-form-item__content {
|
||||
color: #82848a;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.LinkVerificationCode_content {
|
||||
position: fixed;
|
||||
top: 40%;
|
||||
bottom: 40%;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -412,6 +412,7 @@ export default {
|
||||
// 保存基本信息
|
||||
handleSave(isAutoCommit, isCheck = false) {
|
||||
return new Promise((resolve, reject) => {
|
||||
isCheck = false
|
||||
if (this.IsOnlyUploadFile && !isCheck) {
|
||||
if (!this.form.UserName) {
|
||||
this.$message.warning(this.$t("trials:researchForm:message:notUserName"))
|
||||
|
||||
@@ -191,7 +191,6 @@ export default {
|
||||
EquipmentControlFieldList.forEach(item => {
|
||||
this.EquipmentControlFieldList.push(item.FiledName)
|
||||
})
|
||||
console.log(this.EquipmentControlFieldList, 'this.EquipmentControlFieldList')
|
||||
this.list = TrialSiteEquipmentSurveyList
|
||||
this.state = trialSiteSurvey.State
|
||||
this.$forceUpdate()
|
||||
|
||||
@@ -154,8 +154,8 @@ import NoticeForm from './components/from'
|
||||
import Pagination from '@/components/Pagination'
|
||||
const searchDataDefault = () => {
|
||||
return {
|
||||
Asc: true,
|
||||
SortField: '',
|
||||
Asc: false,
|
||||
SortField: 'PublishedTime',
|
||||
NoticeContent: null,
|
||||
FileName: null,
|
||||
NoticeTypeEnum: null,
|
||||
|
||||
@@ -178,7 +178,7 @@ export default {
|
||||
updateUser(this.user)
|
||||
.then((res) => {
|
||||
this.isDisabled = false
|
||||
this.$message.success('Updated successfully')
|
||||
this.$message.success(this.$t("common:message:updatedSuccessfully"))
|
||||
})
|
||||
.catch(() => {
|
||||
this.isDisabled = false
|
||||
@@ -190,7 +190,7 @@ export default {
|
||||
this.user.Id = res.Result.Id
|
||||
this.user.UserCode = res.Result.UserCode
|
||||
this.$emit('getUserId', res.Result.Id)
|
||||
this.$message.success('Added successfully')
|
||||
this.$message.success(this.$t("common:message:addedSuccessfully"))
|
||||
this.$router.push({ path: '/system/user/list' })
|
||||
})
|
||||
.catch(() => {
|
||||
@@ -308,63 +308,63 @@ export default {
|
||||
UserWorkLanguage: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please Select',
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
Roles: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please Select',
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
IsZhiZhun: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please Select',
|
||||
message: this.$t("common:ruleMessage:select"),
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
OrganizationName: [
|
||||
{ required: true, message: 'Please specify', trigger: 'blur' },
|
||||
{ required: true, message: this.$t("common:ruleMessage:specify"), trigger: 'blur' },
|
||||
],
|
||||
LastName: [
|
||||
{ required: true, message: 'Please specify', trigger: 'blur' },
|
||||
{ max: 50, message: 'The maximum length is 50' },
|
||||
{ required: true, message: this.$t("common:ruleMessage:specify"), trigger: 'blur' },
|
||||
{ max: 50, message: this.$t("trials:researchForm:formRule:maxLength") },
|
||||
],
|
||||
FirstName: [
|
||||
{ required: true, message: 'Please specify', trigger: 'blur' },
|
||||
{ max: 50, message: 'The maximum length is 50' },
|
||||
{ required: true, message: this.$t("common:ruleMessage:specify"), trigger: 'blur' },
|
||||
{ max: 50, message: this.$t("trials:researchForm:formRule:maxLength") },
|
||||
],
|
||||
Phone: [
|
||||
{
|
||||
max: 20,
|
||||
min: 7,
|
||||
message: 'The length is 7 to 20',
|
||||
message: this.$t("system:userInfo:ruleMessage:length7to20"),
|
||||
trigger: ['blur'],
|
||||
},
|
||||
],
|
||||
EMail: [
|
||||
{
|
||||
required: true,
|
||||
message: 'Please input the email address',
|
||||
message: this.$t("common:ruleMessage:specify"),
|
||||
trigger: 'blur',
|
||||
},
|
||||
{
|
||||
// type: 'email',
|
||||
pattern: new RegExp(this.$reg().EmailRegexStr),
|
||||
message: 'Please input the correct email address',
|
||||
message: this.$t("trials:site:ruleMessage:correctEmail"),
|
||||
trigger: ['blur'],
|
||||
},
|
||||
{ max: 50, message: 'The maximum length is 50' },
|
||||
{ max: 50, message: this.$t("trials:researchForm:formRule:maxLength") },
|
||||
],
|
||||
Sex: [{ required: true, message: 'Please specify', trigger: 'blur' }],
|
||||
Sex: [{ required: true, message: this.$t("common:ruleMessage:specify"), trigger: 'blur' }],
|
||||
Status: [
|
||||
{ required: true, message: 'Please specify', trigger: 'blur' },
|
||||
{ required: true, message: this.$t("common:ruleMessage:specify"), trigger: 'blur' },
|
||||
],
|
||||
DepartmentName: [{ max: 50, message: 'The maximum length is 50' }],
|
||||
PositionName: [{ max: 50, message: 'The maximum length is 50' }],
|
||||
DepartmentName: [{ max: 50, message: this.$t("trials:researchForm:formRule:maxLength") }],
|
||||
PositionName: [{ max: 50, message: this.$t("trials:researchForm:formRule:maxLength") }],
|
||||
},
|
||||
userTypeOptions: [],
|
||||
isDisabled: false,
|
||||
|
||||
@@ -388,7 +388,7 @@ export default {
|
||||
this.shareLoading = false
|
||||
if (res.IsSuccess) {
|
||||
this.validityPeriod = res.Result.LinkExpirationTime
|
||||
this.LinkVerificationCode = res.Result.LinkVerificationCode || this.$route.query.researchProgramNo
|
||||
this.LinkVerificationCode = res.Result.LinkVerificationCode || res.Result.ResearchProgramNo
|
||||
if (!this.validityPeriod) {
|
||||
this.LinkVerificationCode = null
|
||||
}
|
||||
|
||||
@@ -1222,7 +1222,7 @@ export default {
|
||||
cornerstoneTools.addToolForElement(element, RectangleRoiTool, { configuration: { allowEmptyLabel: true, handleRadius: false, drawHandlesOnHover: true, hideHandlesIfMoving: true } })
|
||||
} else if (toolName === 'Probe' && (parseInt(localStorage.getItem('CriterionType')) === 21)) {
|
||||
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 5, handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) {
|
||||
} else if (toolName === 'Probe' && parseInt(localStorage.getItem('CriterionType')) === 22) {
|
||||
cornerstoneTools.addToolForElement(element, ProbeTool, { configuration: { fixedRadius: 12, unit: 'mm', handleRadius: true, drawHandlesOnHover: true, hideHandlesIfMoving: true, digits: this.digitPlaces } })
|
||||
} else {
|
||||
cornerstoneTools.addToolForElement(element, apiTool)
|
||||
@@ -1675,7 +1675,10 @@ export default {
|
||||
cornerstone.getDefaultViewportForImage(this.canvas, image)
|
||||
)
|
||||
},
|
||||
|
||||
getInfo() {
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
return image
|
||||
},
|
||||
toggleDicomInfo() {
|
||||
this.toolState.dicomInfoVisible = !this.toolState.dicomInfoVisible
|
||||
if (this.toolState.dicomInfoVisible) {
|
||||
|
||||
@@ -218,9 +218,9 @@
|
||||
<div class="text">{{ $t('trials:reading:button:screenShot') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
<el-popover v-model="keySeriesPopoverVisible" placement="bottom" trigger="click" popper-class="key-series-popper"
|
||||
@show="showKeySeriesPanel">
|
||||
|
||||
<el-popover v-model="keySeriesPopoverVisible" placement="bottom" trigger="click"
|
||||
popper-class="key-series-popper" @show="showKeySeriesPanel">
|
||||
<ul class="key-series-list">
|
||||
<li v-if="keyStack && keyStack.taskBlindName" class="key-series-header">
|
||||
<div class="key-series-header-top">
|
||||
@@ -422,7 +422,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-tooltip v-if="trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2" v-hasPermi="['role:ir']"
|
||||
<el-tooltip v-if="trialCriterion.ImageUploadEnum > 0"
|
||||
class="item" effect="dark" :content="$t('trials:reading:button:upload')" placement="bottom">
|
||||
<div class="tool-wrapper">
|
||||
<div class="icon" @click.prevent="openUploadImage('upload')">
|
||||
@@ -431,15 +431,7 @@
|
||||
<div class="text">{{ $t('trials:reading:button:upload') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="trialCriterion.ImageDownloadEnum > 0" v-hasPermi="[
|
||||
'role:ir',
|
||||
'role:mim',
|
||||
'role:mc',
|
||||
'role:pm',
|
||||
'role:apm',
|
||||
'role:ea',
|
||||
'role:qa',
|
||||
]" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<el-tooltip v-if="trialCriterion.ImageDownloadEnum > 0" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<div class="tool-wrapper">
|
||||
<div class="icon" @click.prevent="openUploadImage('download')">
|
||||
<i class="el-icon-download svg-icon" />
|
||||
@@ -447,6 +439,10 @@
|
||||
<div class="text">{{ $t('trials:reading:button:download') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<label for="Replacement" style="color: #fff;cursor: pointer;">
|
||||
替换
|
||||
</label>
|
||||
<input type="file" id="Replacement" @change="beginScanFiles($event, 'replace')" style="display: none;">
|
||||
<div style="margin-left:auto;">
|
||||
<div style="padding:5px;display: flex;">
|
||||
<!-- 手册 -->
|
||||
@@ -563,7 +559,7 @@
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</transition>
|
||||
|
||||
|
||||
@@ -596,7 +592,7 @@
|
||||
</el-tab-pane>
|
||||
<!-- 其他 -->
|
||||
<el-tab-pane :label="$t('trials:reading:tab:others')" name="3">
|
||||
<Others v-if="activeName === '3'" :imageToolType="1"/>
|
||||
<Others v-if="activeName === '3'" :imageToolType="1" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
|
||||
@@ -708,10 +704,11 @@
|
||||
</el-dialog>
|
||||
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" :isReading="true"
|
||||
:StudyInstanceUID="StudyInstanceUID" />
|
||||
<download-dicom-and-nonedicom v-if="downloadImageVisible" :subject-id="uploadSubjectId"
|
||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :task-id="taskId"
|
||||
:visible.sync="downloadImageVisible" />
|
||||
:visible.sync="downloadImageVisible" :isReading="true" />
|
||||
<!-- 签名框 -->
|
||||
<el-dialog v-if="signVisible" :visible.sync="signVisible" :close-on-click-modal="false" width="600px"
|
||||
custom-class="base-dialog-wrapper">
|
||||
@@ -767,6 +764,8 @@ import const_ from '@/const/sign-code'
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
import SystemInfo from "@/utils/systemInfo";
|
||||
import md5 from 'js-md5'
|
||||
import { changeFile } from "./upload.js"
|
||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||
export default {
|
||||
name: 'DicomViewer',
|
||||
components: {
|
||||
@@ -845,6 +844,10 @@ export default {
|
||||
default() {
|
||||
return true
|
||||
}
|
||||
},
|
||||
Loading: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -978,7 +981,10 @@ export default {
|
||||
fullScreenWidth: window.innerWidth - 570 + 'px',
|
||||
fullScreenHeight: window.innerHeight - 130 + 'px',
|
||||
|
||||
ManualsClose: false
|
||||
ManualsClose: false,
|
||||
fileKey: null,
|
||||
file: null,
|
||||
StudyInstanceUID: null
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1129,7 +1135,7 @@ export default {
|
||||
DicomEvent.$on('imageLocation', async (measuredData) => {
|
||||
return new Promise(async resolve => {
|
||||
if (!measuredData) return
|
||||
|
||||
|
||||
await this.imageLocation(measuredData)
|
||||
resolve()
|
||||
})
|
||||
@@ -1197,7 +1203,7 @@ export default {
|
||||
} else if (this.CriterionType === 22) {
|
||||
this.setToolActive('Probe', true, null, 'tableQuestion')
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
window.addEventListener('beforeunload', () => {
|
||||
if (this.petctWindow) {
|
||||
@@ -1213,6 +1219,12 @@ export default {
|
||||
this.AspectRatio = windowWidth / windowHeight
|
||||
};
|
||||
this.getSystemInfoReading()
|
||||
DicomEvent.$on('sendStudyFile', (study) => {
|
||||
let image = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getInfo()
|
||||
study.visitTaskList = this.visitTaskList
|
||||
this.$emit("update:Loading", true)
|
||||
changeFile('IR', this.file, study, image)
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
DicomEvent.$off('updateImage')
|
||||
@@ -1236,6 +1248,11 @@ export default {
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
beginScanFiles(e, key) {
|
||||
this.fileKey = key
|
||||
this.file = e.target.files[0]
|
||||
DicomEvent.$emit('getStudyFile')
|
||||
},
|
||||
handleReadingChart(e) {
|
||||
this.$emit('handleReadingChart', e)
|
||||
},
|
||||
@@ -1283,6 +1300,10 @@ export default {
|
||||
if (idx > -1) {
|
||||
this.taskId = this.visitTaskList[idx].VisitTaskId
|
||||
}
|
||||
let image = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getInfo()
|
||||
let dataset = dcmjs.data.DicomMessage.readFile(image.data.byteArray.buffer)
|
||||
this.StudyInstanceUID = dataset.dict['0020000D'].Value[0]
|
||||
dataset = null
|
||||
this.uploadSubjectCode = localStorage.getItem("subjectCode")
|
||||
this.uploadSubjectId = localStorage.getItem("subjectId")
|
||||
this.uploadTrialCriterion = this.trialCriterion
|
||||
@@ -1451,7 +1472,7 @@ export default {
|
||||
// } catch (err) {
|
||||
// console.error(err)
|
||||
// }
|
||||
const series = this.getSeriesInfoByMark(visitTaskId, {lesionName: kf.MarkName})
|
||||
const series = this.getSeriesInfoByMark(visitTaskId, { lesionName: kf.MarkName })
|
||||
if (!series) return
|
||||
this.loadImageStack(series)
|
||||
},
|
||||
@@ -2496,7 +2517,7 @@ export default {
|
||||
this.readingTaskState = 2
|
||||
await store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 2 })
|
||||
await store.dispatch('reading/setCurrentReadingTaskState', 2)
|
||||
const res = await getAutoCutNextTask({imageToolType: 1})
|
||||
const res = await getAutoCutNextTask({ imageToolType: 1 })
|
||||
var isAutoTask = res.Result.AutoCutNextTask
|
||||
if (isAutoTask) {
|
||||
window.location.reload()
|
||||
@@ -2609,7 +2630,7 @@ export default {
|
||||
await this.$confirm(this.$t('trials:lugano:fusionDialog:message:checkSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
|
||||
showCancelButton: false,
|
||||
type: 'warning'
|
||||
}).catch(() => {})
|
||||
}).catch(() => { })
|
||||
return
|
||||
}
|
||||
if (this.ctSeriesInfo.instanceCount > 400) {
|
||||
|
||||
@@ -33,17 +33,21 @@
|
||||
<div v-for="item in qs.Childrens" :key="item.Id">
|
||||
<div v-if="item.Type === 'basicTable'" class="flex-row" style="margin:3px 0;">
|
||||
<div class="title">{{ item.QuestionName }}</div>
|
||||
<div v-if="item.LesionType === 104 && readingTaskState < 2">
|
||||
<div class="add-icon" @click.prevent="downloadTpl">
|
||||
<div v-if="item.LesionType === 104">
|
||||
<div
|
||||
class="add-icon" @click.prevent="downloadTpl" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-download" />
|
||||
</div>
|
||||
<div class="add-icon" style="margin: 0 5px;"
|
||||
@click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
|
||||
@click.prevent="uploadTpl(item.LesionType, item.QuestionName)" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-upload2" />
|
||||
</div>
|
||||
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
|
||||
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-plus" />
|
||||
</div>
|
||||
<div class="add-icon" @click.prevent="handleView(item)">
|
||||
<i class="el-icon-view" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -222,6 +226,7 @@
|
||||
<script>
|
||||
import { saveTaskQuestion, submitTableQuestion, deleteReadingRowAnswer } from '@/api/trials'
|
||||
import { resetReadingTask, getIVUSTemplate } from '@/api/reading'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import DicomEvent from './../DicomEvent'
|
||||
import store from '@/store'
|
||||
import { mapGetters } from 'vuex'
|
||||
@@ -284,7 +289,8 @@ export default {
|
||||
sRoiEndDistanceId: '',
|
||||
sRoiDistanceId: '',
|
||||
rowSaveLoadingMap: {},
|
||||
dialogSaveLoading: false
|
||||
dialogSaveLoading: false,
|
||||
childWindows: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -324,11 +330,13 @@ export default {
|
||||
DicomEvent.$on('refreshQuestions', _ => {
|
||||
this.refreshQuestions()
|
||||
})
|
||||
window.addEventListener('beforeunload', this.closeAllChildWindows)
|
||||
},
|
||||
beforeDestroy() {
|
||||
DicomEvent.$off('setCollapseActive')
|
||||
DicomEvent.$off('getUnSaveTarget')
|
||||
DicomEvent.$off('refreshQuestions')
|
||||
window.removeEventListener('beforeunload', this.closeAllChildWindows)
|
||||
},
|
||||
methods: {
|
||||
handleReadingChart(e) {
|
||||
@@ -739,6 +747,24 @@ export default {
|
||||
this.addOrEdit.visible = true
|
||||
this.addOrEdit.lesionType = row.LesionType
|
||||
},
|
||||
handleView(item) {
|
||||
localStorage.setItem('taskBlindName', this.taskBlindName)
|
||||
localStorage.setItem('isReadingShowSubjectInfo', this.isReadingShowSubjectInfo)
|
||||
let token = getToken()
|
||||
let routeData = this.$router.resolve({ path: `/ecrfList?trialId=${this.$route.query.trialId}&visitTaskId=${this.visitTaskId}&questionId=${item.Id}&TokenKey=${token}` })
|
||||
const win = window.open(routeData.href, '_blank')
|
||||
if (win) {
|
||||
this.childWindows.push(win)
|
||||
}
|
||||
},
|
||||
closeAllChildWindows() {
|
||||
this.childWindows.forEach(win => {
|
||||
if (win && !win.closed) {
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
this.childWindows = []
|
||||
},
|
||||
async saveFormData() {
|
||||
if (this.dialogSaveLoading) return
|
||||
this.dialogSaveLoading = true
|
||||
|
||||
@@ -33,17 +33,20 @@
|
||||
<div v-for="item in qs.Childrens" :key="item.Id">
|
||||
<div v-if="item.Type === 'basicTable'" class="flex-row" style="margin:3px 0;">
|
||||
<div class="title">{{ item.QuestionName }}</div>
|
||||
<div v-if="(item.LesionType === 104) && readingTaskState < 2">
|
||||
<div class="add-icon" @click.prevent="downloadTpl(item.LesionType)">
|
||||
<div v-if="(item.LesionType === 104)">
|
||||
<div class="add-icon" @click.prevent="downloadTpl(item.LesionType)" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-download" />
|
||||
</div>
|
||||
<div class="add-icon" style="margin: 0 5px;"
|
||||
@click.prevent="uploadTpl(item.LesionType, item.QuestionName)">
|
||||
@click.prevent="uploadTpl(item.LesionType, item.QuestionName)" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-upload2" />
|
||||
</div>
|
||||
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)">
|
||||
<div class="add-icon" @click.prevent="handleAddOrEdit('add', item)" v-if="readingTaskState < 2">
|
||||
<i class="el-icon-plus" />
|
||||
</div>
|
||||
<div class="add-icon" @click.prevent="handleView(item)">
|
||||
<i class="el-icon-view" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -224,6 +227,7 @@ import { saveTaskQuestion, submitTableQuestion, deleteReadingRowAnswer } from '@
|
||||
import { resetReadingTask, getOCTFCTTemplate, getOCTLipidAngleTemplate } from '@/api/reading'
|
||||
import DicomEvent from './../DicomEvent'
|
||||
import store from '@/store'
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { mapGetters } from 'vuex'
|
||||
import Questions from './../Questions'
|
||||
import QuestionTableFormItem from './QuestionTableFormItem'
|
||||
@@ -285,7 +289,8 @@ export default {
|
||||
sRoiEndDistanceId: '',
|
||||
sRoiDistanceId: '',
|
||||
rowSaveLoadingMap: {},
|
||||
dialogSaveLoading: false
|
||||
dialogSaveLoading: false,
|
||||
childWindows: []
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -325,11 +330,13 @@ export default {
|
||||
DicomEvent.$on('refreshQuestions', _ => {
|
||||
this.refreshQuestions()
|
||||
})
|
||||
window.addEventListener('beforeunload', this.closeAllChildWindows)
|
||||
},
|
||||
beforeDestroy() {
|
||||
DicomEvent.$off('setCollapseActive')
|
||||
DicomEvent.$off('getUnSaveTarget')
|
||||
DicomEvent.$off('refreshQuestions')
|
||||
window.removeEventListener('beforeunload', this.closeAllChildWindows)
|
||||
},
|
||||
methods: {
|
||||
handleReadingChart(e) {
|
||||
@@ -755,6 +762,27 @@ export default {
|
||||
this.addOrEdit.visible = true
|
||||
this.addOrEdit.lesionType = row.LesionType
|
||||
},
|
||||
handleView(item) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close()
|
||||
}
|
||||
localStorage.setItem('taskBlindName', this.taskBlindName)
|
||||
localStorage.setItem('isReadingShowSubjectInfo', this.isReadingShowSubjectInfo)
|
||||
let token = getToken()
|
||||
let routeData = this.$router.resolve({ path: `/ecrfList?trialId=${this.$route.query.trialId}&visitTaskId=${this.visitTaskId}&questionId=${item.Id}&TokenKey=${token}` })
|
||||
const win = window.open(routeData.href, '_blank')
|
||||
if (win) {
|
||||
this.childWindows.push(win)
|
||||
}
|
||||
},
|
||||
closeAllChildWindows() {
|
||||
this.childWindows.forEach(win => {
|
||||
if (win && !win.closed) {
|
||||
win.close()
|
||||
}
|
||||
})
|
||||
this.childWindows = []
|
||||
},
|
||||
async saveFormData() {
|
||||
if (this.dialogSaveLoading) return
|
||||
this.dialogSaveLoading = true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="dicom-container">
|
||||
<div class="dicom-container" v-loading="loading">
|
||||
<div :class="{ 'dicom-list': true, studyHide: !studyShow }">
|
||||
<div class="container">
|
||||
<div class="related-study-wrapper">
|
||||
@@ -27,7 +27,8 @@
|
||||
class="study-wrapper">
|
||||
<StudyList v-if="selectArr.includes(s.VisitTaskId)" :ref="s.VisitTaskId" :visit-task-id="s.VisitTaskId"
|
||||
:trial-id="trialId" :subject-visit-id="s.VisitId" :task-blind-name="s.TaskBlindName"
|
||||
:is-reading-show-subject-info="isReadingShowSubjectInfo" @loadImageStack="loadImageStack"
|
||||
:is-reading-show-subject-info="isReadingShowSubjectInfo"
|
||||
:is-reading-task-view-in-order="isReadingTaskViewInOrder" @loadImageStack="loadImageStack"
|
||||
@previewNoneDicoms="previewNoneDicoms" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,7 +39,7 @@
|
||||
</div>
|
||||
<div class="dicom-viewer">
|
||||
<div class="container">
|
||||
<DicomViewer v-if="activeTaskVisitId" ref="dicomViewer" :is-show="isShow"
|
||||
<DicomViewer v-if="activeTaskVisitId" ref="dicomViewer" :is-show="isShow" :Loading.sync="loading"
|
||||
:question-form-change-state="questionFormChangeState" :question-form-change-num="questionFormChangeNum"
|
||||
:is-exists-clinical-data="isExistsClinicalData" :is-exists-no-dicom-file="isExistsNoDicomFile"
|
||||
:is-reading-show-subject-info="isReadingShowSubjectInfo" :studyShow="studyShow"
|
||||
|
||||
@@ -505,15 +505,23 @@ export default {
|
||||
var idx = item.Childrens.findIndex(i => i.QuestionMark === 8)
|
||||
var idxLoc = item.Childrens.findIndex(i => i.QuestionMark === 10)
|
||||
var state = item.Childrens.findIndex(i => i.QuestionMark === 7)
|
||||
if (this.CriterionType === 22) {
|
||||
idx = item.Childrens.findIndex(i => i.QuestionMark === 1106)
|
||||
}
|
||||
if (idx > -1) {
|
||||
if (item.Childrens[idx].Answer.length > 0) {
|
||||
var k = item.Childrens[idx].Answer.findIndex(v => v.Answer !== '')
|
||||
var part = ''
|
||||
if (obj.IsCanEditPosition) {
|
||||
part = `${item.Childrens[idx].Answer[k].Answer}--${item.Childrens[idxLoc].Answer[k].Answer}`
|
||||
if (this.CriterionType === 22) {
|
||||
part = item.Childrens[idx].Answer[k].Answer ? this.$fd('Liver4Segmentation', parseInt(item.Childrens[idx].Answer[k].Answer)) : ''
|
||||
} else {
|
||||
part = `${item.Childrens[idx].Answer[k].Answer}`
|
||||
if (obj.IsCanEditPosition) {
|
||||
part = `${item.Childrens[idx].Answer[k].Answer}--${item.Childrens[idxLoc].Answer[k].Answer}`
|
||||
} else {
|
||||
part = `${item.Childrens[idx].Answer[k].Answer}`
|
||||
}
|
||||
}
|
||||
|
||||
if (item.SplitOrMergeLesionName && k > -1) {
|
||||
// obj.QuestionName = `${obj.QuestionName} --${part} (Split from ${item.SplitOrMergeLesionName})`
|
||||
obj.QuestionName = `${obj.QuestionName} --${part}`
|
||||
@@ -531,6 +539,7 @@ export default {
|
||||
this.$set(obj, 'Answers', Answers)
|
||||
// obj.QuestionName = `${obj.QuestionName} `
|
||||
} else if (!item.SplitOrMergeLesionName && k > -1) {
|
||||
console.log(part)
|
||||
obj.QuestionName = `${obj.QuestionName}--${part}`
|
||||
const Answers = {}
|
||||
if (state >= 0) {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div v-loading="loading" class="study-wrapper">
|
||||
<h4 v-if="isReadingShowSubjectInfo" style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;">
|
||||
<h4 v-if="isReadingShowSubjectInfo"
|
||||
style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;">
|
||||
{{ subjectCode }}
|
||||
</h4>
|
||||
<h4 v-if="isReadingShowSubjectInfo" style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;margin-bottom: 5px;">
|
||||
<h4 v-if="isReadingShowSubjectInfo"
|
||||
style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;margin-bottom: 5px;">
|
||||
{{ taskBlindName }}
|
||||
</h4>
|
||||
<div class="ps">
|
||||
@@ -14,116 +16,103 @@
|
||||
<!-- 关键序列 -->
|
||||
{{ $t('trials:reading:title:keySeries') }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="dicom-desc"
|
||||
style="white-space: normal;"
|
||||
>
|
||||
<div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
|
||||
<span v-if="taskInfo && taskInfo.IsShowStudyName && study.StudyName" :title="study.StudyName">
|
||||
{{study.StudyName}}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="study-meta-line" :title="study.Modalities">
|
||||
<span class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||
<span class="study-modality">{{ study.Modalities }}({{ study.SeriesCount }})</span>
|
||||
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
||||
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
||||
<h4>{{ $t('trials:ptData:title') }}</h4>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
||||
<span>{{ study.PatientSex }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
||||
<span>{{ study.PatientWeight }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
||||
<span>{{ study.RadionuclideTotalDose }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
||||
<span>{{ study.RadionuclideHalfLife }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
||||
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
||||
<span>{{ study.AcquisitionTime }}</span>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-document"
|
||||
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
||||
</el-popover>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="study.Description" class="study-desc-text" :title="study.Description">{{ study.Description }}</div>
|
||||
<div v-else class="dicom-desc" style="white-space: normal;">
|
||||
<div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
|
||||
<span v-if="taskInfo && taskInfo.IsShowStudyName && study.StudyName" :title="study.StudyName">
|
||||
{{ study.StudyName }}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="study-meta-line" :title="study.Modalities">
|
||||
<span v-if="isReadingTaskViewInOrder !== 0" class="study-code" :title="study.StudyCode">{{
|
||||
study.StudyCode }}</span>
|
||||
<span class="study-modality">{{ study.Modalities }}({{ study.SeriesCount }})</span>
|
||||
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
||||
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
||||
<h4>{{ $t('trials:ptData:title') }}</h4>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:patientSex') }}</label>
|
||||
<span>{{ study.PatientSex }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:patientWeight') }}</label>
|
||||
<span>{{ study.PatientWeight }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:totalDose') }}</label>
|
||||
<span>{{ study.RadionuclideTotalDose }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:halfLife') }}</label>
|
||||
<span>{{ study.RadionuclideHalfLife }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:injectTime') }}</label>
|
||||
<span>{{ study.RadiopharmaceuticalStartTime }}</span>
|
||||
</div>
|
||||
<div class="patient-info-row">
|
||||
<label>{{ $t('trials:ptData:label:acquisitionTime') }}</label>
|
||||
<span>{{ study.AcquisitionTime }}</span>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-document"
|
||||
style="font-size: 15px;cursor: pointer;color: #f5f7fa;" />
|
||||
</el-popover>
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
<div v-if="study.Description" class="study-desc-text" :title="study.Description">{{ study.Description }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<div class="series">
|
||||
<div
|
||||
v-for="(series, i) in study.SeriesList"
|
||||
:key="i"
|
||||
style="position:relative;margin-top:5px;"
|
||||
series-type="current"
|
||||
@click="showSeriesImage(index,i,series)"
|
||||
>
|
||||
<div v-for="(series, i) in study.SeriesList" :key="i" style="position:relative;margin-top:5px;"
|
||||
series-type="current" @click="showSeriesImage(index, i, series)">
|
||||
|
||||
<div
|
||||
:class="{'series-active': i==seriesIndex && index === studyIndex}"
|
||||
class="series-wrapper"
|
||||
>
|
||||
<el-image
|
||||
class="image-preview"
|
||||
:src="series.previewImageUrl"
|
||||
fit="fill"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<div :class="{ 'series-active': i == seriesIndex && index === studyIndex }" class="series-wrapper">
|
||||
<el-image class="image-preview" :src="series.previewImageUrl" fit="fill" crossorigin="anonymous" />
|
||||
<div class="image-desc">
|
||||
<div class="flex-div">
|
||||
<div style="width: 40px;display: flex;flex-direction: row;justify-content: space-between;">
|
||||
<div v-if="!study.IsCriticalSequence">#{{ series.seriesNumber }}</div>
|
||||
<div v-if="series.isDicom && series.prefetchInstanceCount<series.instanceCount * 100 && series.modality!== 'SR'">
|
||||
<div
|
||||
v-if="series.isDicom && series.prefetchInstanceCount < series.instanceCount * 100 && series.modality !== 'SR'">
|
||||
<!-- 下载 -->
|
||||
<el-tooltip v-if="!series.isLoading" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play" style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;" @click.stop="loadSeries(series,index,i)" />
|
||||
<el-tooltip v-if="!series.isLoading" class="item" effect="dark"
|
||||
:content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play"
|
||||
style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;"
|
||||
@click.stop="loadSeries(series, index, i)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-tooltip v-else-if="series.isDicom && series.prefetchInstanceCount === 0 &&series.modality!== 'SR'" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play" style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;" @click.stop="loadSeries(series,index,i)" />
|
||||
<el-tooltip
|
||||
v-else-if="series.isDicom && series.prefetchInstanceCount === 0 && series.modality !== 'SR'"
|
||||
class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play"
|
||||
style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;"
|
||||
@click.stop="loadSeries(series, index, i)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-if="series.isExistMutiFrames && series.instanceCount > 1">
|
||||
<el-popover
|
||||
placement="right"
|
||||
trigger="hover"
|
||||
popper-class="instance_frame_wrapper"
|
||||
>
|
||||
<el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
|
||||
<div class="frame_list">
|
||||
<div
|
||||
v-for="(instance, idx) in series.instanceInfoList"
|
||||
:key="instance.Id"
|
||||
class="frame_content"
|
||||
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
||||
@click.stop="showMultiFrames(index,series, i, instance)"
|
||||
>
|
||||
<div v-for="(instance, idx) in series.instanceInfoList" :key="instance.Id"
|
||||
class="frame_content" :class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{ 'margin-bottom': idx < series.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click.stop="showMultiFrames(index, series, i, instance)">
|
||||
<div>
|
||||
<div>{{ instance.InstanceNumber }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ?
|
||||
instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
||||
<i slot="reference" class="el-icon-connection"
|
||||
style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
@@ -131,7 +120,7 @@
|
||||
<el-tooltip class="item" effect="dark" :content="series.description" placement="right">
|
||||
<div style="">{{ series.description }}</div>
|
||||
</el-tooltip>
|
||||
|
||||
|
||||
</p>
|
||||
|
||||
<p v-show="series.sliceThickness && !study.IsCriticalSequence">
|
||||
@@ -145,9 +134,11 @@
|
||||
</p>
|
||||
|
||||
<div class="flex-div">
|
||||
<div v-if="measureData && measureData.findIndex(v=>v.SeriesId === series.seriesId && v.MeasureData) > -1">
|
||||
<div
|
||||
v-if="measureData && measureData.findIndex(v => v.SeriesId === series.seriesId && v.MeasureData) > -1">
|
||||
<!-- 有标注 -->
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:marked')" placement="right">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:marked')"
|
||||
placement="right">
|
||||
<i class="el-icon-star-on" style="font-size: 16px;color: #ff5722;" />
|
||||
</el-tooltip>
|
||||
|
||||
@@ -155,10 +146,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="series.isDicom && series.prefetchInstanceCount>0 && series.prefetchInstanceCount<series.instanceCount * 100" style="width: 100%;">
|
||||
<el-progress
|
||||
:percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))"
|
||||
/>
|
||||
<div
|
||||
v-if="series.isDicom && series.prefetchInstanceCount > 0 && series.prefetchInstanceCount < series.instanceCount * 100"
|
||||
style="width: 100%;">
|
||||
<el-progress :percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -168,24 +159,19 @@
|
||||
</div>
|
||||
|
||||
<div class="sr-wrapper">
|
||||
<el-dialog
|
||||
:visible.sync="srDialogVisible"
|
||||
:custom-class="isSrFullscreen?'sr-full-dialog-container':'sr-dialog-container'"
|
||||
:show-close="false"
|
||||
:close-on-click-modal="false"
|
||||
:fullscreen="isSrFullscreen"
|
||||
>
|
||||
<el-dialog :visible.sync="srDialogVisible"
|
||||
:custom-class="isSrFullscreen ? 'sr-full-dialog-container' : 'sr-dialog-container'" :show-close="false"
|
||||
:close-on-click-modal="false" :fullscreen="isSrFullscreen">
|
||||
<span slot="title" class="dialog-footer">
|
||||
<div style="position: absolute;right: 20px;top: 10px;">
|
||||
<svg-icon :icon-class="isSrFullscreen?'exit-fullscreen':'fullscreen'" style="cursor: pointer;font-size: 20px;color:#000;" @click="isSrFullscreen=!isSrFullscreen" />
|
||||
<svg-icon icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;" @click="srDialogVisible = false" />
|
||||
<svg-icon :icon-class="isSrFullscreen ? 'exit-fullscreen' : 'fullscreen'"
|
||||
style="cursor: pointer;font-size: 20px;color:#000;" @click="isSrFullscreen = !isSrFullscreen" />
|
||||
<svg-icon icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;"
|
||||
@click="srDialogVisible = false" />
|
||||
</div>
|
||||
</span>
|
||||
<div style="height: 100%;margin:0;">
|
||||
<SrList
|
||||
v-if="srDialogVisible"
|
||||
:sr-info="srInfo"
|
||||
/>
|
||||
<SrList v-if="srDialogVisible" :sr-info="srInfo" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -226,6 +212,10 @@ export default {
|
||||
isReadingShowSubjectInfo: {
|
||||
type: Boolean,
|
||||
required: true
|
||||
},
|
||||
isReadingTaskViewInOrder: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
@@ -292,6 +282,9 @@ export default {
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
this.measureData = this.visitTaskList[idx].MeasureData
|
||||
})
|
||||
DicomEvent.$on("getStudyFile", () => {
|
||||
DicomEvent.$emit('sendStudyFile', { studyList: this.studyList, studyIndex: this.studyIndex, seriesIndex: this.seriesIndex, visitTaskId: this.visitTaskId })
|
||||
})
|
||||
|
||||
// DicomEvent.$on('setReadingState', readingTaskState => {
|
||||
// var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
@@ -316,7 +309,7 @@ export default {
|
||||
methods: {
|
||||
debounce(fn, delay) {
|
||||
let timer = null
|
||||
return function() {
|
||||
return function () {
|
||||
const context = this
|
||||
const args = arguments
|
||||
clearTimeout(timer)
|
||||
@@ -330,7 +323,7 @@ export default {
|
||||
// 初始化待渲染序列
|
||||
this.getInitSeries().then((res) => {
|
||||
requestPoolManager.startTaskTimer()
|
||||
res.map(async(item) => {
|
||||
res.map(async (item) => {
|
||||
// this.loadInitialImage(item)
|
||||
const imageId = item.imageIds[item.imageIdIndex]
|
||||
const p = parseInt(new Date().getTime())
|
||||
@@ -340,7 +333,7 @@ export default {
|
||||
}
|
||||
})
|
||||
var i = -1
|
||||
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
|
||||
var isReadingTaskViewInOrder = parseInt(this.isReadingTaskViewInOrder)
|
||||
if (isReadingTaskViewInOrder === 2) {
|
||||
// 受试者内随机
|
||||
i = res.length === 2 ? 1 : -1
|
||||
@@ -427,7 +420,7 @@ export default {
|
||||
|
||||
async getInitSeries() {
|
||||
var seriesList = []
|
||||
var isReadingTaskViewInOrder = parseInt(this.$router.currentRoute.query.isReadingTaskViewInOrder)
|
||||
var isReadingTaskViewInOrder = parseInt(this.isReadingTaskViewInOrder)
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
this.studyList = this.visitTaskList[idx].StudyList
|
||||
const studyList = this.visitTaskList[idx].StudyList.filter(i => i.IsDicom)
|
||||
@@ -452,8 +445,8 @@ export default {
|
||||
this.studyIndex = obj.studyIndex
|
||||
this.seriesIndex = obj.seriesIndex
|
||||
seriesList.push(obj.series)
|
||||
this.activeNames = [`${this.studyList[ this.studyIndex].StudyId}`]
|
||||
this.studyList[ obj.studyIndex].SeriesList[obj.seriesIndex].isFirstRender = true
|
||||
this.activeNames = [`${this.studyList[this.studyIndex].StudyId}`]
|
||||
this.studyList[obj.studyIndex].SeriesList[obj.seriesIndex].isFirstRender = true
|
||||
} else {
|
||||
if (this.studyList.length > 0) {
|
||||
// 初始化问题表单
|
||||
@@ -490,7 +483,7 @@ export default {
|
||||
this.studyIndex = secondObj.studyIndex
|
||||
this.seriesIndex = secondObj.seriesIndex
|
||||
seriesList.push(secondObj.series)
|
||||
this.studyList[ secondObj.studyIndex].SeriesList[secondObj.seriesIndex].isFirstRender = true
|
||||
this.studyList[secondObj.studyIndex].SeriesList[secondObj.seriesIndex].isFirstRender = true
|
||||
this.studyIndex = secondObj.studyIndex
|
||||
this.seriesIndex = secondObj.seriesIndex
|
||||
|
||||
@@ -523,7 +516,7 @@ export default {
|
||||
// const instanceList = seriesList[srIdx].instanceList
|
||||
const imageIds = seriesList[srIdx].imageIds
|
||||
// const filterStr = seriesList[srIdx].isExistMutiFrames ? `frame=${measureDatas[i].MeasureData.frame}&instanceId=${measureDatas[i].InstanceId}` : `instanceId=${measureDatas[i].InstanceId}`
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(k=>k.Id === measureDatas[i].InstanceId)
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(k => k.Id === measureDatas[i].InstanceId)
|
||||
let filterStr = ''
|
||||
if (instanceIndex > -1 && seriesList[srIdx].isExistMutiFrames) {
|
||||
if (seriesList[srIdx].instanceInfoList[instanceIndex].NumberOfFrames > 0) {
|
||||
@@ -607,7 +600,7 @@ export default {
|
||||
// const instanceList = seriesList[srIdx].imageIds
|
||||
const imageIds = seriesList[srIdx].imageIds
|
||||
// const filterStr = seriesList[srIdx].isExistMutiFrames ? `frame=${measureDatas[mIdx].MeasureData.frame}&instanceId=${measureDatas[mIdx].InstanceId}` : `instanceId=${measureDatas[mIdx].InstanceId}`
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(i=>i.Id === measureDatas[mIdx].InstanceId)
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(i => i.Id === measureDatas[mIdx].InstanceId)
|
||||
let filterStr = ''
|
||||
if (instanceIndex > -1 && seriesList[srIdx].isExistMutiFrames) {
|
||||
if (seriesList[srIdx].instanceInfoList[instanceIndex].NumberOfFrames > 0) {
|
||||
@@ -964,15 +957,17 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.study-wrapper{
|
||||
::v-deep .el-progress-bar__inner{
|
||||
.study-wrapper {
|
||||
::v-deep .el-progress-bar__inner {
|
||||
transition: width 0s ease;
|
||||
}
|
||||
|
||||
width:100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
.dicom-desc{
|
||||
|
||||
.dicom-desc {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
@@ -981,6 +976,7 @@ export default {
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.study-meta-line {
|
||||
// display: grid;
|
||||
// grid-template-columns: minmax(0, 1fr) auto;
|
||||
@@ -990,6 +986,7 @@ export default {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.study-meta-main {
|
||||
display: block;
|
||||
min-width: 0;
|
||||
@@ -997,11 +994,13 @@ export default {
|
||||
overflow-wrap: anywhere;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.study-code,
|
||||
.study-modality {
|
||||
white-space: normal;
|
||||
margin: 0 2px;
|
||||
}
|
||||
|
||||
.study-desc-text {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
@@ -1013,19 +1012,23 @@ export default {
|
||||
overflow-anchor: none;
|
||||
touch-action: auto;
|
||||
}
|
||||
|
||||
.series-active {
|
||||
background-color: #607d8b!important;
|
||||
border: 1px solid #607d8b!important;
|
||||
background-color: #607d8b !important;
|
||||
border: 1px solid #607d8b !important;
|
||||
}
|
||||
::v-deep .el-progress__text{
|
||||
|
||||
::v-deep .el-progress__text {
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
.series{
|
||||
|
||||
.series {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
.series-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -1038,11 +1041,13 @@ export default {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #404040;
|
||||
background-color: #3a3a3a;
|
||||
.el-progress__text{
|
||||
|
||||
.el-progress__text {
|
||||
display: none;
|
||||
}
|
||||
.el-progress-bar{
|
||||
padding-right:0px;
|
||||
|
||||
.el-progress-bar {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
@@ -1051,9 +1056,11 @@ export default {
|
||||
border: 2px solid #252525;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image-desc {
|
||||
vertical-align: top;
|
||||
p{
|
||||
|
||||
p {
|
||||
width: 95px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -1062,7 +1069,8 @@ export default {
|
||||
color: #ddd;
|
||||
margin: 0px;
|
||||
line-height: 1.5;
|
||||
div{
|
||||
|
||||
div {
|
||||
width: 95px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -1070,7 +1078,8 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.flex-div{
|
||||
|
||||
.flex-div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@@ -1087,21 +1096,25 @@ export default {
|
||||
|
||||
}
|
||||
}
|
||||
::v-deep .el-collapse{
|
||||
|
||||
::v-deep .el-collapse {
|
||||
border: none;
|
||||
.el-collapse-item{
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item {
|
||||
background-color: #000 !important;
|
||||
color: #ddd;
|
||||
|
||||
}
|
||||
.el-collapse-item__content{
|
||||
padding-bottom:5px;
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 5px;
|
||||
background-color: #000 !important;
|
||||
}
|
||||
.el-collapse-item__header{
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item__header {
|
||||
background-color: #000 !important;
|
||||
color: #ddd;
|
||||
border-bottom-color:#5a5a5a;
|
||||
border-bottom-color: #5a5a5a;
|
||||
padding-left: 1px;
|
||||
min-height: 40px;
|
||||
height: auto;
|
||||
@@ -1110,35 +1123,42 @@ export default {
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
.el-collapse-item__arrow{
|
||||
|
||||
.el-collapse-item__arrow {
|
||||
align-self: flex-start;
|
||||
margin-top: 2px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.sr-wrapper{
|
||||
::v-deep .el-dialog{
|
||||
|
||||
.sr-wrapper {
|
||||
::v-deep .el-dialog {
|
||||
background: #fff !important;
|
||||
border: 1px solid #ddd;
|
||||
|
||||
// color: #ddd;
|
||||
.el-dialog__title{
|
||||
color:#fff;
|
||||
.el-dialog__title {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
::v-deep .sr-dialog-container{
|
||||
|
||||
::v-deep .sr-dialog-container {
|
||||
margin-top: 50px !important;
|
||||
width:75%;
|
||||
height:80%;
|
||||
width: 75%;
|
||||
height: 80%;
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 10px;
|
||||
height: calc(100% - 50px);
|
||||
|
||||
::v-deep .el-dialog__body {
|
||||
padding: 10px;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
.el-dialog__header{
|
||||
|
||||
.el-dialog__header {
|
||||
position: relative;
|
||||
}
|
||||
.sr-full-dialog-container{
|
||||
::v-deep .is-fullscreen .el-dialog__body{
|
||||
|
||||
.sr-full-dialog-container {
|
||||
::v-deep .is-fullscreen .el-dialog__body {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
@@ -1146,25 +1166,29 @@ export default {
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
.instance_frame_wrapper{
|
||||
.instance_frame_wrapper {
|
||||
min-width: 120px;
|
||||
background-color: #2c2c2c;
|
||||
border: 1px solid #2c2c2c;
|
||||
padding: 5px;
|
||||
}
|
||||
.frame_list{
|
||||
|
||||
.frame_list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.instance_frame_wrapper ::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
|
||||
|
||||
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
.frame_content{
|
||||
|
||||
.frame_content {
|
||||
height: 50px;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
@@ -1173,6 +1197,7 @@ export default {
|
||||
font-size: 12px;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
|
||||
.frame_content:hover {
|
||||
/* font-weight: bold; */
|
||||
/* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
|
||||
@@ -1181,6 +1206,7 @@ export default {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
@@ -1193,6 +1219,7 @@ export default {
|
||||
line-height: 1;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.patient-info-popper {
|
||||
font-size: 12px;
|
||||
color: #ddd;
|
||||
@@ -1217,7 +1244,7 @@ export default {
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
.patient-info-popper .patient-info-row + .patient-info-row {
|
||||
.patient-info-popper .patient-info-row+.patient-info-row {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<template>
|
||||
<div class="table-list-container" v-loading="loading">
|
||||
<h3 v-if="isReadingShowSubjectInfo">
|
||||
<span v-if="subjectCode">{{ subjectCode }} </span>
|
||||
<span style="margin-left:5px;">{{ taskBlindName }}</span>
|
||||
</h3>
|
||||
<h3 v-if="tableQuestion && tableQuestion.GroupName">
|
||||
{{ language === 'en' ? tableQuestion.GroupEnName : tableQuestion.GroupName }}
|
||||
</h3>
|
||||
<h4 v-if="tableQuestion && tableQuestion.QuestionName">
|
||||
{{ tableQuestion.QuestionName }}
|
||||
</h4>
|
||||
<el-table
|
||||
v-if="tableQuestion && tableQuestion.Type === 'basicTable' && tableQuestion.TableQuestions"
|
||||
:ref="tableQuestion.Id"
|
||||
:data="tableQuestion.TableQuestions.Answers"
|
||||
height="100%"
|
||||
>
|
||||
<el-table-column
|
||||
v-for="q of tableQuestion.TableQuestions.Questions"
|
||||
:key="q.Id"
|
||||
:prop="q.Id"
|
||||
:label="q.QuestionName"
|
||||
show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
<span v-if="q.Unit > 0 && !isNaN(parseFloat(scope.row[q.Id]))">
|
||||
{{ `${scope.row[q.Id]} ${$fd('ValueUnit', parseInt(q.Unit))}` }}
|
||||
</span>
|
||||
<span v-else-if="q.DictionaryCode">
|
||||
{{`${scope.row[q.Id] instanceof Array ? scope.row[q.Id].map(item => $fd(q.DictionaryCode,
|
||||
parseInt(item))).join(',') : $fd(q.DictionaryCode, parseInt(scope.row[q.Id]))}`}}
|
||||
</span>
|
||||
<span v-else-if="q.OptionTypeEnum === 1">
|
||||
{{ `${scope.row[q.Id] instanceof Array ? scope.row[q.Id].join(',') : scope.row[q.Id]}` }}
|
||||
</span>
|
||||
<span v-else>
|
||||
{{ `${scope.row[q.Id]}` }}
|
||||
</span>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { getFilterTableQuestion } from '@/api/reading'
|
||||
import store from '@/store'
|
||||
import { mapGetters } from 'vuex'
|
||||
import { changeURLStatic } from '@/utils/history.js'
|
||||
export default {
|
||||
name: 'DicomTableList',
|
||||
data() {
|
||||
return {
|
||||
isReadingShowSubjectInfo: false,
|
||||
subjectCode: null,
|
||||
taskBlindName: null,
|
||||
questionId: null,
|
||||
tableQuestion: null,
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters(['language'])
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.TokenKey) {
|
||||
store.dispatch('user/setToken', this.$route.query.TokenKey)
|
||||
changeURLStatic('TokenKey', '')
|
||||
}
|
||||
this.subjectCode = localStorage.getItem('subjectCode')
|
||||
this.taskBlindName = localStorage.getItem('taskBlindName')
|
||||
this.isReadingShowSubjectInfo = localStorage.getItem('isReadingShowSubjectInfo')
|
||||
this.getList()
|
||||
},
|
||||
methods: {
|
||||
async getList() {
|
||||
try {
|
||||
this.loading = true
|
||||
let params = {
|
||||
trialId: this.$route.query.trialId,
|
||||
visitTaskId: this.$route.query.visitTaskId,
|
||||
questionId: this.$route.query.questionId
|
||||
}
|
||||
let res = await getFilterTableQuestion(params)
|
||||
if (res.IsSuccess) {
|
||||
this.tableQuestion = res.Result
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
},
|
||||
resetList() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.table-list-container {
|
||||
height: 100%;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
flex-shrink: 0;
|
||||
margin: 10px 0 10px;
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,205 @@
|
||||
import { dcmUpload } from '@/utils/dcmUpload/dcmUpload'
|
||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||
import { deleteImageCache, getAnonymizeInfo, updateModality } from '@/api/reading'
|
||||
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 Vue from 'vue'
|
||||
function 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 canvasToBlob(canvas)
|
||||
resolve(blob)
|
||||
} else {
|
||||
resolve()
|
||||
}
|
||||
})
|
||||
}).catch((reason) => {
|
||||
reason()
|
||||
})
|
||||
}
|
||||
function canvasToBlob(canvas) {
|
||||
return new Promise((resolve) => {
|
||||
canvas.toBlob((blob) => {
|
||||
resolve(blob)
|
||||
})
|
||||
})
|
||||
}
|
||||
async function UpdateModality(params) {
|
||||
try {
|
||||
let res = await updateModality(params)
|
||||
if (res.IsSuccess) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
async function getAnonymize(VisitTaskId, SubjectVisitId) {
|
||||
try {
|
||||
let params = {}
|
||||
if (VisitTaskId) {
|
||||
params.VisitTaskId = VisitTaskId
|
||||
} else {
|
||||
params.SubjectVisitId = SubjectVisitId
|
||||
}
|
||||
let res = await getAnonymizeInfo(params)
|
||||
if (res.IsSuccess) {
|
||||
return res.Result
|
||||
}
|
||||
return false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
async function deleteCache(path) {
|
||||
try {
|
||||
let params = {
|
||||
path
|
||||
}
|
||||
let res = await deleteImageCache(params)
|
||||
if (res.IsSuccess) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
return false
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 0002,0003 MediaStorageSOPInstanceUID
|
||||
* 0008,0018 SOPInstanceUID
|
||||
* 0020,000D StudyInstanceUID
|
||||
* 0020,000E SeriesInstanceUID
|
||||
*
|
||||
*/
|
||||
export async function changeFile(key, file, study, image) {
|
||||
// console.log(image, 'image')
|
||||
// return console.log(study, 'study')
|
||||
let dataset = dcmjs.data.DicomMessage.readFile(image.data.byteArray.buffer)
|
||||
// console.log(dataset, 'dataset')
|
||||
let MediaStorageSOPInstanceUID = dataset.meta['00020003'].Value[0]
|
||||
let SOPInstanceUID = dataset.dict['00080018'].Value[0]
|
||||
let StudyInstanceUID = dataset.dict['0020000D'].Value[0]
|
||||
let SeriesInstanceUID = dataset.dict['0020000E'].Value[0]
|
||||
// let Modality = dataset.dict['00080060'].Value[0]
|
||||
let { visitTaskId, visitTaskList = [], studyList, studyIndex, seriesIndex, seriesList, currentSeriesIndex } = study
|
||||
let series = key === 'IR' ? studyList[studyIndex].SeriesList[seriesIndex] : seriesList[currentSeriesIndex]
|
||||
console.log(series, 'seriesId')
|
||||
let index = visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
|
||||
let config = null
|
||||
if (key === 'IR') {
|
||||
config = await getAnonymize(visitTaskId)
|
||||
} else {
|
||||
config = await getAnonymize(null, series.subjectVisitId)
|
||||
}
|
||||
if (!config) return false
|
||||
config.AnonymizeFixedList.push({
|
||||
Element: '0003',
|
||||
Group: '0002',
|
||||
ReplaceValue: MediaStorageSOPInstanceUID,
|
||||
Id: 'MediaStorageSOPInstanceUID'
|
||||
})
|
||||
config.AnonymizeFixedList.push({
|
||||
Element: '0018',
|
||||
Group: '0008',
|
||||
ReplaceValue: SOPInstanceUID,
|
||||
Id: 'SOPInstanceUID'
|
||||
})
|
||||
config.AnonymizeFixedList.push({
|
||||
Element: '000D',
|
||||
Group: '0020',
|
||||
ReplaceValue: StudyInstanceUID,
|
||||
Id: 'StudyInstanceUID'
|
||||
})
|
||||
config.AnonymizeFixedList.push({
|
||||
Element: '000E',
|
||||
Group: '0020',
|
||||
ReplaceValue: SeriesInstanceUID,
|
||||
Id: 'SeriesInstanceUID'
|
||||
})
|
||||
let uploadBatchId = Vue.prototype.$guid()
|
||||
let path = image.imageId.split(`wadouri:${Vue.prototype.OSSclientConfig.basePath}`)[1].split("?")[0]
|
||||
let res = await dcmUpload(
|
||||
{
|
||||
path: path,
|
||||
file: file,
|
||||
speed: true,
|
||||
},
|
||||
config,
|
||||
(percentage, checkpoint, lastPer) => {
|
||||
|
||||
},
|
||||
{
|
||||
fileName: file.name,
|
||||
fileSize: file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 1,
|
||||
// trialId: params.trialId,
|
||||
subjectId: key === 'IR' ? localStorage.getItem("subjectId") : series.subjectId,
|
||||
subjectVisitId: key === 'IR' ? visitTaskList[index].VisitId : series.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (!res || !res.url) return false
|
||||
let Modality = res.Modality
|
||||
let fileId =
|
||||
cornerstoneWADOImageLoader.wadouri.fileManager.add(
|
||||
file
|
||||
)
|
||||
let blob = await dicomToPng(
|
||||
fileId,
|
||||
image.columns,
|
||||
image.rows
|
||||
)
|
||||
let thumbnailPath = series.previewImageUrl.split(Vue.prototype.OSSclientConfig.basePath)[1]
|
||||
let OSSclient = Vue.prototype.OSSclient
|
||||
try {
|
||||
let seriesRes = await OSSclient.put(thumbnailPath, blob, {
|
||||
fileName: thumbnailPath.split('/')[thumbnailPath.split('/').length - 1],
|
||||
fileSize: blob.size,
|
||||
fileType: 'image/jpeg',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 2,
|
||||
// trialId: params.trialId,
|
||||
subjectId: key === 'IR' ? localStorage.getItem("subjectId") : series.subjectId,
|
||||
subjectVisitId: key === 'IR' ? visitTaskList[index].VisitId : series.subjectVisitId,
|
||||
})
|
||||
console.log(seriesRes, 'seriesRes')
|
||||
if (!seriesRes || !seriesRes.url) return false
|
||||
res = await Promise.all([deleteCache(path), deleteCache(thumbnailPath)])
|
||||
if (!res) return false
|
||||
let params = {
|
||||
Modality,
|
||||
SeriesId: series.seriesId,
|
||||
IsCRCReplace: key === 'IR' ? false : true
|
||||
}
|
||||
res = await UpdateModality(params)
|
||||
if (!res) return false
|
||||
window.location.reload(true)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
<div class="info-image">
|
||||
<div v-show="mousePosition.mo">
|
||||
Pos: {{ mousePosition.x ? mousePosition.x.toFixed(0) : '' }}, {{ mousePosition.y ? mousePosition.y.toFixed(0) :
|
||||
'' }}
|
||||
'' }}
|
||||
</div>
|
||||
<div
|
||||
v-if="(dicomInfo.modality === 'CT' || dicomInfo.modality === 'DR' || dicomInfo.modality === 'CR') && mousePosition.mo">
|
||||
@@ -477,6 +477,10 @@ export default {
|
||||
DicomEvent.$off('updateImage')
|
||||
},
|
||||
methods: {
|
||||
getInfo() {
|
||||
var image = cornerstone.getImage(this.canvas)
|
||||
return image
|
||||
},
|
||||
goViewer(e) {
|
||||
console.log(this.$refs['sliderBox'].clientHeight)
|
||||
var height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
|
||||
|
||||
@@ -309,10 +309,8 @@
|
||||
<div class="text">{{ $t('trials:reading:button:reset') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="
|
||||
trialCriterion.ImageUploadEnum > 0 && currentReadingTaskState < 2
|
||||
" v-hasPermi="['role:ir']" class="item" effect="dark" :content="$t('trials:reading:button:upload')"
|
||||
placement="bottom">
|
||||
<el-tooltip v-if="trialCriterion.ImageUploadEnum > 0" class="item" effect="dark"
|
||||
:content="$t('trials:reading:button:upload')" placement="bottom">
|
||||
<div class="tool-wrapper">
|
||||
<div class="icon" @click.prevent="openUploadImage('upload')">
|
||||
<i class="el-icon-upload2 svg-icon" />
|
||||
@@ -320,15 +318,8 @@
|
||||
<div class="text">{{ $t('trials:reading:button:upload') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
<el-tooltip v-if="trialCriterion.ImageDownloadEnum > 0" v-hasPermi="[
|
||||
'role:ir',
|
||||
'role:mim',
|
||||
'role:mc',
|
||||
'role:pm',
|
||||
'role:apm',
|
||||
'role:ea',
|
||||
'role:qa',
|
||||
]" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<el-tooltip v-if="trialCriterion.ImageDownloadEnum > 0" class="item" effect="dark"
|
||||
:content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<div class="tool-wrapper">
|
||||
<div class="icon" @click.prevent="openUploadImage('download')">
|
||||
<i class="el-icon-download svg-icon" />
|
||||
@@ -336,7 +327,10 @@
|
||||
<div class="text">{{ $t('trials:reading:button:download') }}</div>
|
||||
</div>
|
||||
</el-tooltip>
|
||||
|
||||
<label for="Replacement" style="color: #fff;cursor: pointer;">
|
||||
替换
|
||||
</label>
|
||||
<input type="file" id="Replacement" @change="beginScanFiles($event, 'replace')" style="display: none;">
|
||||
<div style="margin-left: auto">
|
||||
<div style="display: flex;">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:handbooks')" placement="bottom"
|
||||
@@ -411,7 +405,7 @@
|
||||
<WL v-if="activeName === '2'" @getWwcTpl="getWwcTpl" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('trials:reading:tab:others')" name="3">
|
||||
<Others v-if="activeName === '3'" :imageToolType="1"/>
|
||||
<Others v-if="activeName === '3'" :imageToolType="1" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</el-dialog>
|
||||
@@ -448,10 +442,10 @@
|
||||
/> -->
|
||||
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :SubjectId="uploadSubjectId" :SubjectCode="uploadSubjectCode"
|
||||
:Criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible" :VisitTaskId="taskId"
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" />
|
||||
:isReadingTaskViewInOrder="isReadingTaskViewInOrder" :StudyInstanceUID="StudyInstanceUID" :isReading="true" />
|
||||
<download-dicom-and-nonedicom v-if="downloadImageVisible" :SubjectId="uploadSubjectId"
|
||||
:SubjectCode="uploadSubjectCode" :Criterion="uploadTrialCriterion" :TaskId="taskId"
|
||||
:visible.sync="downloadImageVisible" />
|
||||
:visible.sync="downloadImageVisible" :isReading="true" />
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
@@ -478,6 +472,8 @@ import { getDoctorShortcutKey, getUserWLTemplateList } from '@/api/user'
|
||||
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
|
||||
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
|
||||
import { getCriterionReadingInfo, setReadKeyFile } from '@/api/trials'
|
||||
import { changeFile } from "@/views/trials/trials-panel/reading/dicoms/components/upload.js"
|
||||
import dcmjs from '@/utils/dcmUpload/dcmjs'
|
||||
export default {
|
||||
name: 'DicomViewer',
|
||||
components: {
|
||||
@@ -683,7 +679,10 @@ export default {
|
||||
fullScreenWidth: window.innerWidth - 570 + 'px',
|
||||
fullScreenHeight: window.innerHeight - 128 + 'px',
|
||||
|
||||
ManualsClose: false
|
||||
ManualsClose: false,
|
||||
fileKey: null,
|
||||
file: null,
|
||||
StudyInstanceUID: null
|
||||
}
|
||||
},
|
||||
|
||||
@@ -856,6 +855,12 @@ export default {
|
||||
this.loadLinkedImageStack(seriesInfo)
|
||||
console.log('loadLinkedImageStack')
|
||||
})
|
||||
DicomEvent.$on('sendStudyFile', (study) => {
|
||||
let image = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getInfo()
|
||||
study.visitTaskList = this.visitTaskList
|
||||
this.$emit("update:Loading", true)
|
||||
changeFile('IR', this.file, study, image)
|
||||
})
|
||||
},
|
||||
beforeDestroy() {
|
||||
DicomEvent.$off('updateImage')
|
||||
@@ -866,6 +871,11 @@ export default {
|
||||
DicomEvent.$off('loadLinkedImageStack')
|
||||
},
|
||||
methods: {
|
||||
beginScanFiles(e, key) {
|
||||
this.fileKey = key
|
||||
this.file = e.target.files[0]
|
||||
DicomEvent.$emit('getStudyFile')
|
||||
},
|
||||
handleReadingChart(e) {
|
||||
this.$emit('handleReadingChart', e)
|
||||
},
|
||||
@@ -898,6 +908,11 @@ export default {
|
||||
if (idx > -1) {
|
||||
this.taskId = this.visitTaskList[idx].VisitTaskId
|
||||
}
|
||||
let image = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getInfo()
|
||||
let dataset = dcmjs.data.DicomMessage.readFile(image.data.byteArray.buffer)
|
||||
this.StudyInstanceUID = dataset.dict['0020000D'].Value[0]
|
||||
dataset = null
|
||||
console.log(this.StudyInstanceUID, 'StudyInstanceUID')
|
||||
this.uploadSubjectCode = localStorage.getItem("subjectCode")
|
||||
this.uploadSubjectId = localStorage.getItem("subjectId")
|
||||
this.uploadTrialCriterion = this.trialCriterion
|
||||
|
||||
@@ -128,7 +128,7 @@ export default {
|
||||
immediate: true,
|
||||
handler(val) {
|
||||
if (val) {
|
||||
this.readingTaskState = val
|
||||
this.readingTaskState = 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@ export default {
|
||||
if (i > -1) {
|
||||
this.visitTaskId = this.visitTaskList[i].VisitTaskId
|
||||
this.taskBlindName = this.visitTaskList[i].TaskBlindName
|
||||
this.readingTaskState = this.visitTaskList[i].ReadingTaskState
|
||||
this.readingTaskState = 1
|
||||
console.log(this.visitTaskList[i].IsInit)
|
||||
if (!this.visitTaskList[i].IsInit) {
|
||||
var loading = this.$loading({ fullscreen: true })
|
||||
@@ -306,9 +306,9 @@ export default {
|
||||
}
|
||||
this.signVisible = false
|
||||
// 设置当前任务阅片状态为已读
|
||||
this.readingTaskState = 2
|
||||
store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 2 })
|
||||
DicomEvent.$emit('setReadingState', 2)
|
||||
this.readingTaskState = 1
|
||||
store.dispatch('reading/setVisitTaskReadingTaskState', { visitTaskId: this.visitTaskId, readingTaskState: 1 })
|
||||
DicomEvent.$emit('setReadingState', 1)
|
||||
window.opener.postMessage('refreshTaskList', window.location)
|
||||
this.$confirm(this.$t('trials:oncologyReview:title:msg2'), {
|
||||
type: 'warning',
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div v-loading="loading" style="min-height: 500px;">
|
||||
<el-form v-if="isRender" ref="questions" size="small" :model="questionForm" :disabled="readingTaskState >= 2">
|
||||
<el-form v-if="isRender" ref="questions" size="small" :model="questionForm">
|
||||
<template>
|
||||
<QuestionFormItem v-for="question of questions" :key="question.Id" :visitTaskId="visitTaskId"
|
||||
:question="question" :question-form="questionForm" :reading-task-state="readingTaskState"
|
||||
@@ -112,8 +112,8 @@ export default {
|
||||
VisitTaskId: visitTaskId ? visitTaskId : this.visitTaskId
|
||||
}).then(res => {
|
||||
this.IsBaseline = res.OtherInfo.IsBaseline
|
||||
this.readingTaskState = res.OtherInfo.ReadingTaskState
|
||||
DicomEvent.$emit('setReadingState', res.OtherInfo.ReadingTaskState)
|
||||
this.readingTaskState = 1
|
||||
DicomEvent.$emit('setReadingState', 1)
|
||||
res.Result.SinglePage.map((v) => {
|
||||
if (v.Type === 'group' && v.Childrens.length === 0) return
|
||||
if (!v.IsPage && v.Type !== 'group' && v.Type !== 'summary' && v.Type !== 'table' && v.Type !== 'basicTable' && v.Type !== 'number') {
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<template>
|
||||
<div v-loading="loading" class="study-wrapper">
|
||||
<h4 v-if="isReadingShowSubjectInfo" style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;">
|
||||
<h4 v-if="isReadingShowSubjectInfo"
|
||||
style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;">
|
||||
{{ subjectCode }}
|
||||
</h4>
|
||||
<h4 v-if="isReadingShowSubjectInfo" style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;margin-bottom: 5px;">
|
||||
<h4 v-if="isReadingShowSubjectInfo"
|
||||
style="color: #ddd;padding: 5px 0px;margin: 0;text-align: center;background-color: #4c4c4c;margin-bottom: 5px;">
|
||||
{{ taskBlindName }}
|
||||
</h4>
|
||||
<div class="ps">
|
||||
@@ -14,76 +16,61 @@
|
||||
<!-- 关键序列 -->
|
||||
{{ $t('trials:reading:title:keySeries') }}
|
||||
</div>
|
||||
<div
|
||||
v-else
|
||||
class="dicom-desc"
|
||||
style="width: 150px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;"
|
||||
>
|
||||
<div v-else class="dicom-desc"
|
||||
style="width: 150px;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;">
|
||||
<div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;" v-if="!study.StudyName">
|
||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||
<span>{{ study.Modalities }} ({{ study.SeriesCount }})</span>
|
||||
<span>{{ study.Modalities }} ({{ study.SeriesCount }})</span>
|
||||
</div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;" v-else>
|
||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||
<span v-if="taskInfo && taskInfo.IsShowStudyName" :title="study.StudyName">
|
||||
{{study.StudyName}}
|
||||
{{ study.StudyName }}
|
||||
</span>
|
||||
<div>{{ study.Modalities }} ({{ study.SeriesCount }})</div>
|
||||
</div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;" :title="study.Description">{{ study.Description }}</div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;" :title="study.Description">{{ study.Description
|
||||
}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
<div class="series">
|
||||
<div
|
||||
v-for="(series, i) in study.SeriesList"
|
||||
:key="i"
|
||||
style="position:relative;margin-top:5px;"
|
||||
series-type="current"
|
||||
@click="showSeriesImage(index,i,series)"
|
||||
>
|
||||
<div v-for="(series, i) in study.SeriesList" :key="i" style="position:relative;margin-top:5px;"
|
||||
series-type="current" @click="showSeriesImage(index, i, series)">
|
||||
|
||||
<div
|
||||
:class="{'series-active': i==seriesIndex && index === studyIndex}"
|
||||
class="series-wrapper"
|
||||
>
|
||||
<el-image
|
||||
class="image-preview"
|
||||
:src="series.previewImageUrl"
|
||||
fit="fill"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<div :class="{ 'series-active': i == seriesIndex && index === studyIndex }" class="series-wrapper">
|
||||
<el-image class="image-preview" :src="series.previewImageUrl" fit="fill" crossorigin="anonymous" />
|
||||
<div class="image-desc">
|
||||
<div class="flex-div">
|
||||
<div style="width: 40px;display: flex;flex-direction: row;justify-content: space-between;">
|
||||
<div v-if="!study.IsCriticalSequence">#{{ series.seriesNumber }}</div>
|
||||
<div v-if="series.isDicom && series.prefetchInstanceCount<series.instanceCount * 100 && series.modality!== 'SR'">
|
||||
<div
|
||||
v-if="series.isDicom && series.prefetchInstanceCount < series.instanceCount * 100 && series.modality !== 'SR'">
|
||||
<!-- 下载 -->
|
||||
<el-tooltip v-if="!series.isLoading" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play" style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;" @click.stop="loadSeries(series,index,i)" />
|
||||
<el-tooltip v-if="!series.isLoading" class="item" effect="dark"
|
||||
:content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play"
|
||||
style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;"
|
||||
@click.stop="loadSeries(series, index, i)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-tooltip v-else-if="series.isDicom && series.prefetchInstanceCount === 0 &&series.modality!== 'SR'" class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play" style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;" @click.stop="loadSeries(series,index,i)" />
|
||||
<el-tooltip
|
||||
v-else-if="series.isDicom && series.prefetchInstanceCount === 0 && series.modality !== 'SR'"
|
||||
class="item" effect="dark" :content="$t('trials:reading:button:download')" placement="bottom">
|
||||
<i class="el-icon-video-play"
|
||||
style="font-size: 18px;margin-right: 5px;color: #ffeb3b;cursor: pointer;"
|
||||
@click.stop="loadSeries(series, index, i)" />
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<div v-if="series.isExistMutiFrames && series.instanceCount > 1">
|
||||
<el-popover
|
||||
placement="right"
|
||||
trigger="hover"
|
||||
popper-class="instance_frame_wrapper"
|
||||
>
|
||||
<el-popover placement="right" trigger="hover" popper-class="instance_frame_wrapper">
|
||||
<div class="frame_list">
|
||||
<div
|
||||
v-for="(instance, idx) in series.instanceInfoList"
|
||||
:key="instance.Id"
|
||||
class="frame_content"
|
||||
:class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{'margin-bottom':idx<series.instanceInfoList.length-1? '5px':'0px'}"
|
||||
@click.stop="showMultiFrames(index,series, i, instance)"
|
||||
>
|
||||
<div v-for="(instance, idx) in series.instanceInfoList" :key="instance.Id"
|
||||
class="frame_content" :class="{ 'frame_content_active': activeInstanceId === instance.Id }"
|
||||
:style="{ 'margin-bottom': idx < series.instanceInfoList.length - 1 ? '5px' : '0px' }"
|
||||
@click.stop="showMultiFrames(index, series, i, instance)">
|
||||
<!-- <div>
|
||||
<img
|
||||
class="image-preview"
|
||||
@@ -96,12 +83,14 @@
|
||||
</div> -->
|
||||
<div>
|
||||
<div>{{ instance.InstanceNumber }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ? instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
||||
<div>{{ `${instance.NumberOfFrames > 0 ? instance.KeyFramesList.length > 0 ?
|
||||
instance.KeyFramesList.length : instance.NumberOfFrames : 1} frame` }}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<i slot="reference" class="el-icon-connection" style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
||||
<i slot="reference" class="el-icon-connection"
|
||||
style="font-size: 15px;cursor: pointer;color: #ffeb3b;" />
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
@@ -121,9 +110,11 @@
|
||||
{{ series.modality }}: {{ series.instanceCount }} image
|
||||
</p>
|
||||
<div class="flex-div">
|
||||
<div v-if="measureData && measureData.findIndex(v=>v.SeriesId === series.seriesId && v.MeasureData) > -1">
|
||||
<div
|
||||
v-if="measureData && measureData.findIndex(v => v.SeriesId === series.seriesId && v.MeasureData) > -1">
|
||||
<!-- 有标注 -->
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:marked')" placement="right">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:marked')"
|
||||
placement="right">
|
||||
<i class="el-icon-star-on" style="font-size: 16px;color: #ff5722;" />
|
||||
</el-tooltip>
|
||||
|
||||
@@ -131,10 +122,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="series.isDicom && series.prefetchInstanceCount>0 && series.prefetchInstanceCount<series.instanceCount * 100" style="width: 100%;">
|
||||
<el-progress
|
||||
:percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))"
|
||||
/>
|
||||
<div
|
||||
v-if="series.isDicom && series.prefetchInstanceCount > 0 && series.prefetchInstanceCount < series.instanceCount * 100"
|
||||
style="width: 100%;">
|
||||
<el-progress :percentage="parseInt((series.prefetchInstanceCount / series.instanceCount).toFixed(2))" />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -144,24 +135,19 @@
|
||||
</div>
|
||||
|
||||
<div class="sr-wrapper">
|
||||
<el-dialog
|
||||
:visible.sync="srDialogVisible"
|
||||
:custom-class="isSrFullscreen?'sr-full-dialog-container':'sr-dialog-container'"
|
||||
:show-close="false"
|
||||
:close-on-click-modal="false"
|
||||
:fullscreen="isSrFullscreen"
|
||||
>
|
||||
<el-dialog :visible.sync="srDialogVisible"
|
||||
:custom-class="isSrFullscreen ? 'sr-full-dialog-container' : 'sr-dialog-container'" :show-close="false"
|
||||
:close-on-click-modal="false" :fullscreen="isSrFullscreen">
|
||||
<span slot="title" class="dialog-footer">
|
||||
<div style="position: absolute;right: 20px;top: 10px;">
|
||||
<svg-icon :icon-class="isSrFullscreen?'exit-fullscreen':'fullscreen'" style="cursor: pointer;font-size: 20px;color:#000;" @click="isSrFullscreen=!isSrFullscreen" />
|
||||
<svg-icon icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;" @click="srDialogVisible = false" />
|
||||
<svg-icon :icon-class="isSrFullscreen ? 'exit-fullscreen' : 'fullscreen'"
|
||||
style="cursor: pointer;font-size: 20px;color:#000;" @click="isSrFullscreen = !isSrFullscreen" />
|
||||
<svg-icon icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;"
|
||||
@click="srDialogVisible = false" />
|
||||
</div>
|
||||
</span>
|
||||
<div style="height: 100%;margin:0;">
|
||||
<SrList
|
||||
v-if="srDialogVisible"
|
||||
:sr-info="srInfo"
|
||||
/>
|
||||
<SrList v-if="srDialogVisible" :sr-info="srInfo" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</div>
|
||||
@@ -266,6 +252,9 @@ export default {
|
||||
var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
this.measureData = this.visitTaskList[idx].MeasureData
|
||||
})
|
||||
DicomEvent.$on("getStudyFile", () => {
|
||||
DicomEvent.$emit('sendStudyFile', { studyList: this.studyList, studyIndex: this.studyIndex, seriesIndex: this.seriesIndex, visitTaskId: this.visitTaskId })
|
||||
})
|
||||
// DicomEvent.$on('setReadingState', readingTaskState => {
|
||||
// var idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.visitTaskId)
|
||||
// if (idx > -1) {
|
||||
@@ -282,7 +271,7 @@ export default {
|
||||
// 初始化待渲染序列
|
||||
this.getInitSeries().then((res) => {
|
||||
requestPoolManager.startTaskTimer()
|
||||
res.map(async(item) => {
|
||||
res.map(async (item) => {
|
||||
let imageId = item.imageIds[item.imageIdIndex]
|
||||
const p = parseInt(new Date().getTime())
|
||||
// requestPoolManager.loadAndCacheImagePlus(imageId, item.seriesId, p * 100)
|
||||
@@ -390,15 +379,15 @@ export default {
|
||||
this.seriesIndex = seriesArr[1].seriesIndex
|
||||
this.activeNames = [`${seriesArr[1].studyId}`]
|
||||
}
|
||||
} else if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder === 0){
|
||||
} else if (this.visitTaskList[idx].IsBaseLineTask || isReadingTaskViewInOrder === 0) {
|
||||
// 基线
|
||||
const obj = this.getFirstMarkedSeries(this.visitTaskList[idx].MeasureData, [...this.visitTaskList[idx].StudyList])
|
||||
if (Object.keys(obj).length !== 0) {
|
||||
this.studyIndex = obj.studyIndex
|
||||
this.seriesIndex = obj.seriesIndex
|
||||
seriesList.push(obj.series)
|
||||
this.activeNames = [`${this.studyList[ this.studyIndex].StudyId}`]
|
||||
this.studyList[ obj.studyIndex].SeriesList[obj.seriesIndex].isFirstRender = true
|
||||
this.activeNames = [`${this.studyList[this.studyIndex].StudyId}`]
|
||||
this.studyList[obj.studyIndex].SeriesList[obj.seriesIndex].isFirstRender = true
|
||||
} else {
|
||||
// 初始化问题表单
|
||||
if (this.studyList.length > 0) {
|
||||
@@ -430,7 +419,7 @@ export default {
|
||||
this.studyIndex = secondObj.studyIndex
|
||||
this.seriesIndex = secondObj.seriesIndex
|
||||
seriesList.push(secondObj.series)
|
||||
this.studyList[ secondObj.studyIndex].SeriesList[secondObj.seriesIndex].isFirstRender = true
|
||||
this.studyList[secondObj.studyIndex].SeriesList[secondObj.seriesIndex].isFirstRender = true
|
||||
this.studyIndex = secondObj.studyIndex
|
||||
this.seriesIndex = secondObj.seriesIndex
|
||||
|
||||
@@ -464,7 +453,7 @@ export default {
|
||||
// const isIdx = instanceList.findIndex(is => is.includes(measureDatas[i].InstanceId))
|
||||
const imageIds = seriesList[srIdx].imageIds
|
||||
// let filterStr = seriesList[srIdx].isExistMutiFrames ? `frame=${measureDatas[i].MeasureData.frame}&instanceId=${measureDatas[i].InstanceId}` : `instanceId=${measureDatas[i].InstanceId}`
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(k=>k.Id === measureDatas[i].InstanceId)
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(k => k.Id === measureDatas[i].InstanceId)
|
||||
let filterStr = ''
|
||||
if (instanceIndex > -1 && seriesList[srIdx].isExistMutiFrames) {
|
||||
if (seriesList[srIdx].instanceInfoList[instanceIndex].NumberOfFrames > 0) {
|
||||
@@ -548,7 +537,7 @@ export default {
|
||||
// const instanceList = seriesList[srIdx].instanceList
|
||||
// const isIdx = instanceList.findIndex(is => is.includes(measureDatas[mIdx].InstanceId))
|
||||
const imageIds = seriesList[srIdx].imageIds
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(i=>i.Id === measureDatas[mIdx].InstanceId)
|
||||
let instanceIndex = seriesList[srIdx].instanceInfoList.findIndex(i => i.Id === measureDatas[mIdx].InstanceId)
|
||||
let filterStr = ''
|
||||
if (instanceIndex > -1 && seriesList[srIdx].isExistMutiFrames) {
|
||||
if (seriesList[srIdx].instanceInfoList[instanceIndex].NumberOfFrames > 0) {
|
||||
@@ -658,7 +647,7 @@ export default {
|
||||
this.studyIndex = studyIndex
|
||||
this.seriesIndex = seriesIndex
|
||||
this.studyList[studyIndex].SeriesList[seriesIndex].measureData = this.measureData
|
||||
var dicomStatck = Object.assign({},this.studyList[studyIndex].SeriesList[seriesIndex])
|
||||
var dicomStatck = Object.assign({}, this.studyList[studyIndex].SeriesList[seriesIndex])
|
||||
|
||||
dicomStatck.imageIdIndex = 0
|
||||
this.$emit('loadImageStack', dicomStatck)
|
||||
@@ -707,7 +696,7 @@ export default {
|
||||
this.studyIndex = studyIndex
|
||||
this.seriesIndex = seriesIndex
|
||||
this.studyList[studyIndex].SeriesList[seriesIndex].measureData = this.measureData
|
||||
var dicomStatck = Object.assign({},this.studyList[studyIndex].SeriesList[seriesIndex])
|
||||
var dicomStatck = Object.assign({}, this.studyList[studyIndex].SeriesList[seriesIndex])
|
||||
const imageIds = []
|
||||
if (instanceInfo.KeyFramesList.length > 0) {
|
||||
instanceInfo.KeyFramesList.map(i => {
|
||||
@@ -867,15 +856,17 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.study-wrapper{
|
||||
::v-deep .el-progress-bar__inner{
|
||||
.study-wrapper {
|
||||
::v-deep .el-progress-bar__inner {
|
||||
transition: width 0s ease;
|
||||
}
|
||||
|
||||
width:100%;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
.dicom-desc{
|
||||
|
||||
.dicom-desc {
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
text-align: left;
|
||||
@@ -887,19 +878,23 @@ export default {
|
||||
overflow-anchor: none;
|
||||
touch-action: auto;
|
||||
}
|
||||
|
||||
.series-active {
|
||||
background-color: #607d8b!important;
|
||||
border: 1px solid #607d8b!important;
|
||||
background-color: #607d8b !important;
|
||||
border: 1px solid #607d8b !important;
|
||||
}
|
||||
::v-deep .el-progress__text{
|
||||
|
||||
::v-deep .el-progress__text {
|
||||
color: #ccc;
|
||||
font-size: 12px;
|
||||
}
|
||||
.series{
|
||||
|
||||
.series {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
|
||||
.series-wrapper {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -912,11 +907,13 @@ export default {
|
||||
border-radius: 2px;
|
||||
border: 1px solid #404040;
|
||||
background-color: #3a3a3a;
|
||||
.el-progress__text{
|
||||
|
||||
.el-progress__text {
|
||||
display: none;
|
||||
}
|
||||
.el-progress-bar{
|
||||
padding-right:0px;
|
||||
|
||||
.el-progress-bar {
|
||||
padding-right: 0px;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
@@ -925,9 +922,11 @@ export default {
|
||||
border: 2px solid #252525;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.image-desc {
|
||||
vertical-align: top;
|
||||
p{
|
||||
|
||||
p {
|
||||
width: 95px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -936,7 +935,8 @@ export default {
|
||||
color: #ddd;
|
||||
margin: 0px;
|
||||
line-height: 1.5;
|
||||
div{
|
||||
|
||||
div {
|
||||
width: 95px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@@ -944,7 +944,8 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
.flex-div{
|
||||
|
||||
.flex-div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
@@ -960,76 +961,89 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .el-collapse{
|
||||
|
||||
::v-deep .el-collapse {
|
||||
border: none;
|
||||
.el-collapse-item{
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item {
|
||||
background-color: #000 !important;
|
||||
color: #ddd;
|
||||
|
||||
}
|
||||
.el-collapse-item__content{
|
||||
padding-bottom:5px;
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item__content {
|
||||
padding-bottom: 5px;
|
||||
background-color: #000 !important;
|
||||
}
|
||||
.el-collapse-item__header{
|
||||
background-color: #000!important;
|
||||
|
||||
.el-collapse-item__header {
|
||||
background-color: #000 !important;
|
||||
color: #ddd;
|
||||
border-bottom-color:#5a5a5a;
|
||||
border-bottom-color: #5a5a5a;
|
||||
padding-left: 5px;
|
||||
height: 40px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
.sr-wrapper{
|
||||
::v-deep .el-dialog{
|
||||
|
||||
.sr-wrapper {
|
||||
::v-deep .el-dialog {
|
||||
background: #fff !important;
|
||||
border: 1px solid #ddd;
|
||||
|
||||
// color: #ddd;
|
||||
.el-dialog__title{
|
||||
color:#fff;
|
||||
.el-dialog__title {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
::v-deep .sr-dialog-container{
|
||||
|
||||
::v-deep .sr-dialog-container {
|
||||
margin-top: 50px !important;
|
||||
width:75%;
|
||||
height:80%;
|
||||
width: 75%;
|
||||
height: 80%;
|
||||
}
|
||||
::v-deep .el-dialog__body{
|
||||
padding: 10px;
|
||||
height: calc(100% - 50px);
|
||||
|
||||
::v-deep .el-dialog__body {
|
||||
padding: 10px;
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
.el-dialog__header{
|
||||
|
||||
.el-dialog__header {
|
||||
position: relative;
|
||||
}
|
||||
.sr-full-dialog-container{
|
||||
::v-deep .is-fullscreen .el-dialog__body{
|
||||
|
||||
.sr-full-dialog-container {
|
||||
::v-deep .is-fullscreen .el-dialog__body {
|
||||
height: calc(100% - 50px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
<style>
|
||||
.instance_frame_wrapper{
|
||||
.instance_frame_wrapper {
|
||||
min-width: 120px;
|
||||
background-color: #2c2c2c;
|
||||
border: 1px solid #2c2c2c;
|
||||
padding: 5px;
|
||||
}
|
||||
.frame_list{
|
||||
|
||||
.frame_list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.instance_frame_wrapper ::-webkit-scrollbar {
|
||||
width: 7px;
|
||||
height: 7px;
|
||||
}
|
||||
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
|
||||
|
||||
.instance_frame_wrapper ::-webkit-scrollbar-thumb {
|
||||
border-radius: 10px;
|
||||
background: #d0d0d0;
|
||||
}
|
||||
.frame_content{
|
||||
|
||||
.frame_content {
|
||||
height: 50px;
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
@@ -1038,6 +1052,7 @@ export default {
|
||||
font-size: 12px;
|
||||
border: 1px solid #404040;
|
||||
}
|
||||
|
||||
.frame_content:hover {
|
||||
/* font-weight: bold; */
|
||||
/* box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); */
|
||||
@@ -1046,6 +1061,7 @@ export default {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
}
|
||||
|
||||
.frame_content_active {
|
||||
border-color: #213a54 !important;
|
||||
background-color: #213a54;
|
||||
|
||||
@@ -619,6 +619,14 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .el-dialog.cd-dialog-container {
|
||||
.el-input.is-disabled .el-input__inner {
|
||||
background-color: rgb(245, 247, 250);
|
||||
color: #666;
|
||||
border: 1px solid #dcdfe6;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
::v-deep .dialog-container {
|
||||
|
||||
@@ -12,7 +12,9 @@
|
||||
{ required: true, message: $t('common:ruleMessage:select'), trigger: 'blur' }
|
||||
]">
|
||||
<el-select v-model="fusionForm.studyId" clearable @change="handleStudyIdChange">
|
||||
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode" :value="item.StudyId" />
|
||||
<el-option v-for="item in studyList" :key="item.StudyId"
|
||||
:label="taskInfo.IsReadingTaskViewInOrder !== 0 ? item.StudyCode : `${item.Modalities}(${item.SeriesCount})`"
|
||||
:value="item.StudyId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 融合图像 -->
|
||||
@@ -111,10 +113,12 @@ export default {
|
||||
ctSeries: [],
|
||||
petSeries: [],
|
||||
petctWindow: null,
|
||||
digitPlaces: 2
|
||||
digitPlaces: 2,
|
||||
taskInfo: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
|
||||
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
||||
this.initForm()
|
||||
|
||||
@@ -187,6 +187,7 @@ export default {
|
||||
originalMarkers: [],
|
||||
markers: { top: '', right: '', bottom: '', left: '' },
|
||||
playClipState: false,
|
||||
clipFramesPerSecond: null,
|
||||
wwwcIdx: 2,
|
||||
presetName: '',
|
||||
volumeId: null,
|
||||
@@ -625,6 +626,22 @@ export default {
|
||||
}
|
||||
|
||||
},
|
||||
syncViewportStaticState() {
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
if (!renderingEngine) return
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (!viewport) return
|
||||
|
||||
this.getOrientationMarker()
|
||||
const toolGroup =
|
||||
cornerstoneTools.ToolGroupManager.getToolGroupForViewport(
|
||||
this.viewportId,
|
||||
this.renderingEngineId
|
||||
) || cornerstoneTools.ToolGroupManager.getToolGroup(this.viewportId)
|
||||
if (toolGroup) {
|
||||
toolGroup.setToolEnabled('ScaleOverlay')
|
||||
}
|
||||
},
|
||||
setFullScreen(index) {
|
||||
setTimeout(() => {
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
@@ -727,14 +744,33 @@ export default {
|
||||
}
|
||||
},
|
||||
toggleClipPlay(isPlay, framesPerSecond) {
|
||||
this.playClipState = isPlay
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
if (!renderingEngine) return
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (!viewport?.element) return
|
||||
|
||||
const parsedFramesPerSecond = Number(framesPerSecond)
|
||||
const nextFramesPerSecond = Number.isFinite(parsedFramesPerSecond)
|
||||
? parsedFramesPerSecond
|
||||
: (this.clipFramesPerSecond || 15)
|
||||
const isSameSpeedWhilePlaying = this.playClipState &&
|
||||
isPlay &&
|
||||
this.clipFramesPerSecond === nextFramesPerSecond
|
||||
|
||||
if (isPlay) {
|
||||
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
|
||||
if (isSameSpeedWhilePlaying) return
|
||||
|
||||
cornerstoneTools.utilities.cine.playClip(viewport.element, {
|
||||
framesPerSecond: nextFramesPerSecond,
|
||||
loop: true,
|
||||
waitForRendered: 1
|
||||
})
|
||||
this.clipFramesPerSecond = nextFramesPerSecond
|
||||
this.playClipState = true
|
||||
} else {
|
||||
cornerstoneTools.utilities.cine.stopClip(viewport.element)
|
||||
this.clipFramesPerSecond = null
|
||||
this.playClipState = false
|
||||
}
|
||||
},
|
||||
scrollPage(type) {
|
||||
@@ -1125,6 +1161,7 @@ export default {
|
||||
|
||||
}
|
||||
viewport.render()
|
||||
this.syncViewportStaticState()
|
||||
if (this.currentVoiUpper > 0) {
|
||||
this.voiChange(this.currentVoiUpper)
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@
|
||||
<svg-icon icon-class="lastframe" class="svg-icon" />
|
||||
</div>
|
||||
<select v-model="fps" :title="$t('trials:dicom-show:speed')" class="select-wrapper"
|
||||
:disabled="clipPlaying">
|
||||
@change="handleClipFpsChange">
|
||||
<!-- 默认值 -->
|
||||
<option :value="5">5</option>
|
||||
<option :value="10">10</option>
|
||||
@@ -320,7 +320,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="tool-item" :title="$t('trials:reading:button:upload')"
|
||||
v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']">
|
||||
v-if="trialCriterion.ImageUploadEnum > 0" v-hasPermi="['role:ir']">
|
||||
<div class="tool-wrapper">
|
||||
<div class="icon" @click.prevent="openUploadImage('upload')">
|
||||
<i class="el-icon-upload2 svg-icon" />
|
||||
@@ -582,10 +582,11 @@
|
||||
:renderingEngineId="renderingEngineId" :visitInfo="taskInfo" /> -->
|
||||
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
||||
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" :isReading="true" />
|
||||
<download-dicom-and-nonedicom v-if="downloadImageVisible" :subject-id="uploadSubjectId"
|
||||
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :task-id="taskId"
|
||||
:visible.sync="downloadImageVisible" />
|
||||
:visible.sync="downloadImageVisible" :is-reading-task-view-in-order="isReadingTaskViewInOrder"
|
||||
:isReading="true" />
|
||||
<readingChart ref="readingChart" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1221,12 +1222,7 @@ export default {
|
||||
this.selectArr.push(item.VisitTaskId)
|
||||
}
|
||||
if (item.IsCurrentTask) {
|
||||
this.markedSeriesIds = []
|
||||
annotations.map(i => {
|
||||
if (i.MeasureData && i.MeasureData.seriesId) {
|
||||
this.markedSeriesIds.push(i.MeasureData.seriesId)
|
||||
}
|
||||
})
|
||||
this.syncMarkedSeriesIds(annotations)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1426,7 +1422,7 @@ export default {
|
||||
async initLoader() {
|
||||
await initLibraries()
|
||||
cache.setMaxCacheSize(6 * 1024 * 1024 * 1024)
|
||||
let renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
let renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
if (!renderingEngine) {
|
||||
renderingEngine = new RenderingEngine(renderingEngineId)
|
||||
}
|
||||
@@ -2052,7 +2048,7 @@ export default {
|
||||
|
||||
// this.$refs['ecrf'].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
|
||||
this.$refs[`ecrf_${this.lastViewportTaskId}`][0].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
|
||||
this.markedSeriesIds.push(series.Id)
|
||||
this.syncMarkedSeriesIdsFromState(series.TaskInfo.VisitTaskId)
|
||||
}
|
||||
|
||||
this.setToolsPassive()
|
||||
@@ -2087,16 +2083,14 @@ export default {
|
||||
throw errorMsg
|
||||
}
|
||||
if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
|
||||
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
|
||||
if (index !== -1) {
|
||||
this.markedSeriesIds.splice(index, 1)
|
||||
}
|
||||
this.syncMarkedSeriesIdsFromState(annotation.visitTaskId)
|
||||
} else {
|
||||
const errorMsg = { message: 'annotation Not allowed to operate' }
|
||||
throw errorMsg
|
||||
}
|
||||
} catch (e) {
|
||||
cornerstoneTools.annotation.state.addAnnotation(annotation)
|
||||
this.syncMarkedSeriesIdsFromState(annotation.visitTaskId)
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
for (let i = 0; i < this.cells.length; i++) {
|
||||
const viewportId = `${this.viewportKey}-${i}`
|
||||
@@ -2133,7 +2127,7 @@ export default {
|
||||
annotation.sliceThickness = series.SliceThickness
|
||||
annotation.numberOfFrames = isNaN(parseInt(params.frame)) ? null : parseInt(params.frame)
|
||||
annotation.markTool = annotation.metadata.toolName
|
||||
this.markedSeriesIds.push(series.Id)
|
||||
this.syncMarkedSeriesIdsFromState(series.TaskInfo.VisitTaskId)
|
||||
const operateStateEnum = this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].operateStateEnum
|
||||
const markName = await this.customPrompt(!this.isNumber(operateStateEnum))
|
||||
|
||||
@@ -2275,10 +2269,7 @@ export default {
|
||||
if (!res.IsSuccess) throw ''
|
||||
}
|
||||
}
|
||||
const index = this.markedSeriesIds.indexOf(annotation.seriesId)
|
||||
if (index !== -1) {
|
||||
this.markedSeriesIds.splice(index, 1)
|
||||
}
|
||||
this.syncMarkedSeriesIdsFromState(annotation.visitTaskId)
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
for (let i = 0; i < this.cells.length; i++) {
|
||||
const viewportId = `${this.viewportKey}-${i}`
|
||||
@@ -2291,6 +2282,7 @@ export default {
|
||||
}
|
||||
} catch (e) {
|
||||
cornerstoneTools.annotation.state.addAnnotation(annotation)
|
||||
this.syncMarkedSeriesIdsFromState(annotation.visitTaskId)
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
for (let i = 0; i < this.cells.length; i++) {
|
||||
const viewportId = `${this.viewportKey}-${i}`
|
||||
@@ -2367,6 +2359,22 @@ export default {
|
||||
this.$set(this.visitTaskList[taskIdx], 'Annotations', annotations)
|
||||
this.$set(this.visitTaskList[taskIdx], 'AnnotationUIDs', annotationUIDs)
|
||||
},
|
||||
collectMarkedSeriesIds(list = []) {
|
||||
return [...new Set(
|
||||
list
|
||||
.map(item => item?.MeasureData?.seriesId || item?.seriesId)
|
||||
.filter(Boolean)
|
||||
)]
|
||||
},
|
||||
syncMarkedSeriesIds(list = []) {
|
||||
this.markedSeriesIds = this.collectMarkedSeriesIds(list)
|
||||
},
|
||||
syncMarkedSeriesIdsFromState(visitTaskId = this.taskInfo?.VisitTaskId) {
|
||||
const annotations = cornerstoneTools.annotation.state.getAllAnnotations().filter(item => {
|
||||
return item.visitTaskId === visitTaskId && item.seriesId
|
||||
})
|
||||
this.syncMarkedSeriesIds(annotations)
|
||||
},
|
||||
async resetAnnotations(visitTaskId) {
|
||||
if (this.readingTaskState === 2) return
|
||||
const taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
|
||||
@@ -2401,9 +2409,9 @@ export default {
|
||||
if (i.MeasureData) {
|
||||
const annotation = i.MeasureData
|
||||
cornerstoneTools.annotation.state.addAnnotation(annotation)
|
||||
this.markedSeriesIds.push(annotation.seriesId)
|
||||
}
|
||||
})
|
||||
this.syncMarkedSeriesIds(annotations)
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
for (let i = 0; i < this.cells.length; i++) {
|
||||
const viewportId = `${this.viewportKey}-${i}`
|
||||
@@ -3415,6 +3423,15 @@ export default {
|
||||
this.clipPlaying = !this.clipPlaying
|
||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].toggleClipPlay(isPlay, this.fps)
|
||||
},
|
||||
handleClipFpsChange() {
|
||||
if (!this.clipPlaying) return
|
||||
|
||||
const activeViewportRef = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`]
|
||||
const activeViewport = activeViewportRef && activeViewportRef[0]
|
||||
if (!activeViewport || typeof activeViewport.toggleClipPlay !== 'function') return
|
||||
|
||||
activeViewport.toggleClipPlay(true, this.fps)
|
||||
},
|
||||
// 获取窗宽窗位模板
|
||||
async getWwcTpl() {
|
||||
try {
|
||||
@@ -4037,8 +4054,10 @@ export default {
|
||||
}
|
||||
}
|
||||
}
|
||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true)
|
||||
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
|
||||
if (!this.isActiveViewportAtMeasureLocation(obj.annotation)) {
|
||||
this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series, true)
|
||||
this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
|
||||
}
|
||||
setTimeout(async () => {
|
||||
const divForDownloadViewport = document.querySelector(
|
||||
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
|
||||
@@ -4049,9 +4068,48 @@ export default {
|
||||
}, 200)
|
||||
}
|
||||
},
|
||||
getMeasureImageLocation(measureData = {}) {
|
||||
const referencedImageId = measureData?.metadata?.referencedImageId
|
||||
const referencedImageParams = referencedImageId ? this.getInstanceInfo(referencedImageId) : {}
|
||||
return {
|
||||
visitTaskId: measureData.visitTaskId,
|
||||
studyId: measureData.studyId || measureData.StudyId,
|
||||
seriesId: measureData.seriesId || measureData.SeriesId,
|
||||
instanceId: measureData.instanceId || measureData.InstanceId || referencedImageParams.instanceId || null,
|
||||
frame: measureData.numberOfFrames ?? measureData.NumberOfFrames ?? referencedImageParams.frame
|
||||
}
|
||||
},
|
||||
getActiveViewportImageLocation() {
|
||||
const viewportRef = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`]?.[0]
|
||||
const currentSeries = viewportRef?.series
|
||||
if (!currentSeries) return null
|
||||
const renderingEngine = getRenderingEngine(renderingEngineId)
|
||||
const viewport = renderingEngine?.getViewport(`${this.viewportKey}-${this.activeViewportIndex}`)
|
||||
const currentImageId = viewport?.getCurrentImageId?.()
|
||||
const currentImageParams = currentImageId ? this.getInstanceInfo(currentImageId) : {}
|
||||
return {
|
||||
visitTaskId: currentSeries.TaskInfo?.VisitTaskId,
|
||||
studyId: currentSeries.StudyId,
|
||||
seriesId: currentSeries.Id,
|
||||
instanceId: currentImageParams.instanceId || null,
|
||||
frame: currentImageParams.frame
|
||||
}
|
||||
},
|
||||
isActiveViewportAtMeasureLocation(measureData) {
|
||||
const targetLocation = this.getMeasureImageLocation(measureData)
|
||||
const currentLocation = this.getActiveViewportImageLocation()
|
||||
if (!currentLocation || !targetLocation.seriesId) return false
|
||||
if (targetLocation.visitTaskId && currentLocation.visitTaskId !== targetLocation.visitTaskId) return false
|
||||
if (targetLocation.studyId && currentLocation.studyId !== targetLocation.studyId) return false
|
||||
if (currentLocation.seriesId !== targetLocation.seriesId) return false
|
||||
if (targetLocation.instanceId && currentLocation.instanceId !== targetLocation.instanceId) return false
|
||||
return currentLocation.frame === targetLocation.frame
|
||||
},
|
||||
async getScreenshots(measureData, callback) {
|
||||
if (measureData) {
|
||||
await this.imageLocation(measureData)
|
||||
if (!this.isActiveViewportAtMeasureLocation(measureData.annotation)) {
|
||||
await this.imageLocation(measureData)
|
||||
}
|
||||
const divForDownloadViewport = document.querySelector(
|
||||
`div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
|
||||
)
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
<el-form-item :label="$t('segment:form:label:studyName')" prop="taskBlindName">
|
||||
<el-select v-model="form.studyId" clearable @change="(e) => handleChange(e, 'study')"
|
||||
@clear="(e) => handleClear(e, 'study')">
|
||||
<el-option v-for="item in studyList" :key="item.StudyId" :label="item.StudyCode"
|
||||
<el-option v-for="item in studyList" :key="item.StudyId"
|
||||
:label="taskInfo.IsReadingTaskViewInOrder !== 0 ? item.StudyCode : `${item.Modalities}(${item.SeriesCount})`"
|
||||
:value="item.StudyId" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
@@ -87,12 +88,13 @@ export default {
|
||||
}, trigger: ['blur', 'change']
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
taskInfo: {}
|
||||
}
|
||||
},
|
||||
// mounted() {
|
||||
// this.init()
|
||||
// },
|
||||
mounted() {
|
||||
this.taskInfo = JSON.parse(sessionStorage.getItem('taskInfo'))
|
||||
},
|
||||
methods: {
|
||||
setSeries(series) {
|
||||
this.series = series
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
@click.prevent="setToolActive('CircularEraser')">
|
||||
<svg-icon icon-class="clear" class="svg-icon" />
|
||||
</div>
|
||||
<div :class="['tool-item']">
|
||||
<!-- <div :class="['tool-item']">
|
||||
<input type="file" @change="beginScanFiles($event)">
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="ConfigBox">
|
||||
<div class="EraserConfig"
|
||||
@@ -133,8 +133,8 @@
|
||||
</div>
|
||||
<div class="SegmentConfig">
|
||||
<span>{{ $t('trials:reading:Segmentations:title:Border') }}</span>
|
||||
<el-slider v-model="SegmentConfig.outlineWidth" show-input :step="1" :max="10"
|
||||
input-size="mini" :show-input-controls="false" />
|
||||
<el-slider v-model="SegmentConfig.outlineWidth" show-input :step="1" :max="10" input-size="mini"
|
||||
:show-input-controls="false" />
|
||||
</div>
|
||||
<span class="line" />
|
||||
<div class="SegmentConfig" style="justify-content: flex-start;">
|
||||
@@ -143,7 +143,7 @@
|
||||
</el-switch>
|
||||
<span style="margin-left: 5px;">{{
|
||||
$t('trials:reading:Segmentations:title:InactiveSegmentationsShow')
|
||||
}}</span>
|
||||
}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<template v-if="segmentList.length > 0">
|
||||
@@ -326,7 +326,7 @@
|
||||
<template slot-scope="scope">
|
||||
<el-button type="text" @click.stop="restoreSegmentationVersion(scope.row)">{{
|
||||
$t('trials:reading:Segmentations:button:recovery')
|
||||
}}</el-button>
|
||||
}}</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -602,6 +602,7 @@ export default {
|
||||
brushSize: {
|
||||
handler() {
|
||||
this.setBrushSize(this.activeTool)
|
||||
this.setSegmentConfig()
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
<div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="taskInfo.SubjectCode">
|
||||
{{ taskInfo.SubjectCode }}
|
||||
</div>
|
||||
<div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="visitTaskInfo.TaskBlindName">
|
||||
<div :title="visitTaskInfo.TaskBlindName">
|
||||
<span v-if="taskInfo && !taskInfo.IsReadingShowSubjectInfo">
|
||||
{{ $t('trials:reading:title:taskName') }}
|
||||
</span>
|
||||
{{ visitTaskInfo.TaskBlindName }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -21,7 +24,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<span class="study-meta-line" :title="study.Modalities">
|
||||
<span class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||
<span v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder !== 0" class="study-code" :title="study.StudyCode">{{ study.StudyCode }}</span>
|
||||
<span class="study-modality">{{ `${study.Modalities}(${study.SeriesCount})` }}</span>
|
||||
<span class="patient-info" v-if="['PT、CT', 'CT、PT', 'PET-CT'].includes(study.Modalities)">
|
||||
<el-popover placement="right-start" trigger="hover" popper-class="patient-info-popper">
|
||||
@@ -329,7 +332,13 @@ export default {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #4c4c4c;
|
||||
height: 50px;
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.dicom-desc {
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
|
||||
@click.stop="viewCD(series.TaskInfo.VisitTaskId)" />
|
||||
</div>
|
||||
<h2 v-if="taskInfo.IsReadingShowSubjectInfo" class="subject-info">
|
||||
{{ `${series.TaskInfo.SubjectCode} ${series.TaskInfo.TaskBlindName} ` }}
|
||||
<h2 class="subject-info">
|
||||
{{ taskInfo.IsReadingShowSubjectInfo ? series.TaskInfo.SubjectCode + ' ' + series.TaskInfo.TaskBlindName : series.TaskInfo.TaskBlindName }}
|
||||
</h2>
|
||||
<div>Series: #{{ series.SeriesNumber }}</div>
|
||||
<div v-if="series.Stack">Image: #{{ `${series.SliceIndex + 1}/${series.Stack.length}` }}</div>
|
||||
@@ -150,6 +150,8 @@ export default {
|
||||
originalMarkers: [],
|
||||
markers: { top: '', right: '', bottom: '', left: '' },
|
||||
playClipState: false,
|
||||
clipFramesPerSecond: null,
|
||||
toggleClipPlayTimer: null,
|
||||
wwwcIdx: 2,
|
||||
loading: false,
|
||||
forceFitToWindow: false,
|
||||
@@ -169,6 +171,10 @@ export default {
|
||||
this.resizeObserver.unobserve(this.element)
|
||||
this.resizeObserver.disconnect()
|
||||
}
|
||||
if (this.toggleClipPlayTimer) {
|
||||
clearInterval(this.toggleClipPlayTimer)
|
||||
this.toggleClipPlayTimer = null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
initViewport() {
|
||||
@@ -210,12 +216,11 @@ export default {
|
||||
this.imageInfo.imageOrientationPatient = imagePlaneModule.imageOrientationPatient
|
||||
this.imageInfo.imagePositionPatient = imagePlaneModule.imagePositionPatient
|
||||
this.imageInfo.location = imagePlaneModule.sliceLocation
|
||||
// this.imageInfo.wwwc = `${Math.round(detail.image.windowWidth)}/${Math.round(detail.image.windowCenter)}`
|
||||
this.getOrientationMarker()
|
||||
this.$emit('renderAnnotations', this.series)
|
||||
const toolGroupId = this.viewportId
|
||||
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(toolGroupId)
|
||||
toolGroup.setToolEnabled('ScaleOverlay')
|
||||
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(this.viewportId)
|
||||
if (toolGroup) {
|
||||
toolGroup.setToolEnabled('ScaleOverlay')
|
||||
}
|
||||
},
|
||||
imageRendered(e) {
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
@@ -312,14 +317,61 @@ export default {
|
||||
}
|
||||
},
|
||||
toggleClipPlay(isPlay, framesPerSecond) {
|
||||
this.playClipState = isPlay
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
if (!renderingEngine) return
|
||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
||||
if (!viewport?.element) return
|
||||
|
||||
const parsedFramesPerSecond = Number(framesPerSecond)
|
||||
const nextFramesPerSecond = Number.isFinite(parsedFramesPerSecond)
|
||||
? parsedFramesPerSecond
|
||||
: (this.clipFramesPerSecond || 15)
|
||||
const isSameSpeedWhilePlaying = this.playClipState &&
|
||||
isPlay &&
|
||||
this.clipFramesPerSecond === nextFramesPerSecond
|
||||
|
||||
if (isPlay) {
|
||||
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond, loop: true })
|
||||
if (isSameSpeedWhilePlaying) return
|
||||
|
||||
cornerstoneTools.utilities.cine.stopClip(viewport.element)
|
||||
if (this.toggleClipPlayTimer) {
|
||||
clearInterval(this.toggleClipPlayTimer)
|
||||
this.toggleClipPlayTimer = null
|
||||
}
|
||||
|
||||
const frameInterval = Math.max(16, Math.round(1000 / nextFramesPerSecond))
|
||||
this.toggleClipPlayTimer = setInterval(() => {
|
||||
const imageIds = viewport.getImageIds()
|
||||
if (!imageIds?.length) return
|
||||
|
||||
let index = viewport.getCurrentImageIdIndex() + 1
|
||||
if (index > imageIds.length - 1) {
|
||||
index = 0
|
||||
}
|
||||
|
||||
csUtils.jumpToSlice(viewport.element, {
|
||||
imageIndex: index,
|
||||
debounceLoading: false
|
||||
})
|
||||
}, frameInterval)
|
||||
this.clipFramesPerSecond = nextFramesPerSecond
|
||||
this.playClipState = true
|
||||
} else {
|
||||
cornerstoneTools.utilities.cine.stopClip(viewport.element)
|
||||
if (this.toggleClipPlayTimer) {
|
||||
clearInterval(this.toggleClipPlayTimer)
|
||||
this.toggleClipPlayTimer = null
|
||||
}
|
||||
this.clipFramesPerSecond = null
|
||||
this.playClipState = false
|
||||
}
|
||||
},
|
||||
syncViewportStaticState() {
|
||||
this.getOrientationMarker()
|
||||
this.$emit('renderAnnotations', this.series)
|
||||
const toolGroup = cornerstoneTools.ToolGroupManager.getToolGroup(this.viewportId)
|
||||
if (toolGroup) {
|
||||
toolGroup.setToolEnabled('ScaleOverlay')
|
||||
}
|
||||
},
|
||||
scrollPage(type) {
|
||||
@@ -339,7 +391,13 @@ export default {
|
||||
}
|
||||
// viewport.setImageIdIndex(newImageIdIndex)
|
||||
csUtils.jumpToSlice(viewport.element, { imageIndex: newImageIdIndex })
|
||||
if (this.toggleClipPlayTimer) {
|
||||
clearInterval(this.toggleClipPlayTimer)
|
||||
this.toggleClipPlayTimer = null
|
||||
}
|
||||
cornerstoneTools.utilities.cine.stopClip(viewport.element)
|
||||
this.clipFramesPerSecond = null
|
||||
this.playClipState = false
|
||||
},
|
||||
setZoom(ratio) {
|
||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
||||
@@ -432,6 +490,7 @@ export default {
|
||||
}
|
||||
this.prefetchMetadataInformation(obj.ImageIds, obj.Modality)
|
||||
await viewport.setStack(this.series.Stack, obj.SliceIndex)
|
||||
this.syncViewportStaticState()
|
||||
|
||||
viewport.render()
|
||||
} catch (e) {
|
||||
|
||||
+7
-4
@@ -1,10 +1,12 @@
|
||||
<template>
|
||||
<div class="criterion-form-item">
|
||||
<div v-if="!!question.GroupName && question.Type === 'group'"
|
||||
<div
|
||||
v-if="(!!question.GroupName && question.Type === 'group') && ((question.ShowQuestion === 1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion === 0)"
|
||||
style="font-weight: bold;font-size: 16px;margin: 5px 0px;color:#fff;">
|
||||
{{ question.GroupName }}
|
||||
</div>
|
||||
<div v-if="question.Type === 'table' || question.Type === 'basicTable'"
|
||||
<div
|
||||
v-if="(question.Type === 'table' || question.Type === 'basicTable') && ((question.ShowQuestion === 1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion === 0)"
|
||||
style="font-weight: bold;font-size: 14px;margin: 5px 0px;">
|
||||
<div style="display: flex;justify-content: space-between;align-items: center;color:#fff;margin: 10px 0 5px">
|
||||
<span :title="question.Remark">{{ question.QuestionName }}</span>
|
||||
@@ -14,7 +16,8 @@
|
||||
{{ $t('common:button:add') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<el-table :data="questionForm[question.Id]">
|
||||
<el-table :data="questionForm[question.Id]"
|
||||
v-if="(question.ShowQuestion === 1 && question.ParentTriggerValueList.includes(String(questionForm[question.ParentId]))) || question.ShowQuestion === 0">
|
||||
<el-table-column :label="$t('CustomizeQuestionFormItem:label:OrderMark')" width="60px" show-overflow-tooltip>
|
||||
<template slot-scope="scope">
|
||||
{{ question.OrderMark }}{{ scope.$index + 1 }}
|
||||
@@ -43,7 +46,7 @@
|
||||
<el-button type="text" size="mini" @click="openAddTableCol(question, scope.$index)">
|
||||
{{ question.IsPreinstall ?
|
||||
$t('CustomizeQuestionFormItem:button:assessment') : readingTaskState >= 2 ? $t('common:button:view') :
|
||||
$t('common:button:edit') }}
|
||||
$t('common:button:edit') }}
|
||||
</el-button>
|
||||
<el-button type="text" size="mini" :disabled="addOrEdit.visible"
|
||||
v-if="readingTaskState < 2 && (scope.row.IsCurrentTaskAdd === 'True' || !question.IsCopyLesions || isBaseline) && !question.IsPreinstall && (question.AddDeleteTypeEnum === 0 || (isBaseline && question.AddDeleteTypeEnum === 1) || (!isBaseline && question.AddDeleteTypeEnum === 2))"
|
||||
|
||||
+12
-5
@@ -2,9 +2,16 @@
|
||||
<div v-loading="loading" class="questionList-wrapper">
|
||||
<div class="container">
|
||||
<div class="basic-info">
|
||||
<h3 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo">
|
||||
<span v-if="visitInfo.SubjectCode">{{ visitInfo.SubjectCode }} </span>
|
||||
<span style="margin-left:5px;">{{ visitInfo.TaskBlindName }}</span>
|
||||
<h3>
|
||||
<span v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && visitInfo.SubjectCode" style="margin-right:5px;">
|
||||
{{ visitInfo.SubjectCode }}
|
||||
</span>
|
||||
<span>
|
||||
<span v-if="taskInfo && !taskInfo.IsReadingShowSubjectInfo">
|
||||
{{ $t('trials:reading:title:taskName') }}
|
||||
</span>
|
||||
{{ visitInfo.TaskBlindName }}
|
||||
</span>
|
||||
</h3>
|
||||
<div v-if="readingTaskState < 2">
|
||||
<el-tooltip class="item" effect="dark" :content="$t('trials:dicomReading:message:confirmReset')"
|
||||
@@ -17,7 +24,7 @@
|
||||
<template v-if="rerender">
|
||||
<QuestionFormItem v-for="question of questions" :key="question.Id" :visit-task-id="visitTaskId"
|
||||
:isNoneDicom="isNoneDicom" :question="question" :question-form="questionForm"
|
||||
:reading-task-state="readingTaskState" :criterion-id="criterionId" :calculation-list="calculationList"
|
||||
:reading-task-state="1" :criterion-id="criterionId" :calculation-list="calculationList"
|
||||
:question-mark-info-list="questionMarkInfoList" :questions-mark-status="questionsMarkStatus"
|
||||
:questionsSegmentMarkStatus="questionsSegmentMarkStatus" :is-baseline="isBaseLineTask"
|
||||
@resetFormItemData="resetFormItemData" @setFormItemData="setFormItemData" @getQuestions="getQuestions"
|
||||
@@ -25,7 +32,7 @@
|
||||
@handleReadingChart="handleReadingChart" @saveSegmentBindingAndAnswer="saveSegmentBindingAndAnswer" />
|
||||
</template>
|
||||
|
||||
<el-form-item v-if="readingTaskState < 2">
|
||||
<el-form-item>
|
||||
<div class="action-bar">
|
||||
<!-- <i class="el-icon-warning feedback-icon" @click="openFeedBackTable"
|
||||
:style="{ color: taskInfo && taskInfo.IsExistUnprocessedFeedback ? '#ffeb3b' : '#fff' }" /> -->
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 受试者编号 -->
|
||||
<el-form-item :label="$t('trials:medicalFeedback:table:subjectCode')">
|
||||
<el-form-item v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0" :label="$t('trials:medicalFeedback:table:subjectCode')">
|
||||
<el-input
|
||||
v-model="searchData.SubjectCode"
|
||||
style="width:130px;"
|
||||
@@ -32,7 +32,7 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
<!-- 盲态任务标识 -->
|
||||
<!-- <el-form-item
|
||||
<el-form-item
|
||||
style="margin-bottom:10px"
|
||||
:label="$t('trials:medicalFeedback:table:taskBlindName')"
|
||||
>
|
||||
@@ -41,7 +41,7 @@
|
||||
style="width:100px;"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item> -->
|
||||
</el-form-item>
|
||||
<!-- 任务类型 -->
|
||||
<el-form-item
|
||||
style="margin-bottom:10px"
|
||||
@@ -172,6 +172,7 @@
|
||||
|
||||
<!-- 受试者编号 -->
|
||||
<el-table-column
|
||||
v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0"
|
||||
prop="SubjectCode"
|
||||
min-width="100"
|
||||
:label="$t('trials:medicalFeedback:table:subjectCode')"
|
||||
@@ -310,7 +311,6 @@
|
||||
<el-table-column
|
||||
:label="$t('common:action:action')"
|
||||
min-width="100"
|
||||
fixed="right"
|
||||
>
|
||||
<template slot-scope="scope">
|
||||
<!-- 查看 -->
|
||||
@@ -409,12 +409,14 @@ export default {
|
||||
chatForm: { visible: false, title: '' }, // 质询记录
|
||||
auditVisible: false,
|
||||
trialCriterionList: [],
|
||||
TrialReadingCriterionId: '0'
|
||||
TrialReadingCriterionId: '0',
|
||||
otherInfo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
TrialReadingCriterionId(v) {
|
||||
if (v) {
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
@@ -437,6 +439,7 @@ export default {
|
||||
getIRMedicalFeedbackList(this.searchData).then(res => {
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
this.otherInfo = res.OtherInfo
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
@@ -454,7 +457,11 @@ export default {
|
||||
},
|
||||
handleReply(row) {
|
||||
this.currentRow = { ...row }
|
||||
this.chatForm.title = `${this.$t('trials:medicalFeedback:title:qaRecord')} (${row.SubjectCode} ${row.TaskBlindName})`
|
||||
if (this.otherInfo && this.otherInfo.IsReadingTaskViewInOrder !== 0) {
|
||||
this.chatForm.title = `${this.$t('trials:medicalFeedback:title:qaRecord')} (${row.SubjectCode} ${row.TaskBlindName})`
|
||||
} else {
|
||||
this.chatForm.title = `${this.$t('trials:medicalFeedback:title:qaRecord')} (${row.TaskBlindName})`
|
||||
}
|
||||
this.chatForm.visible = true
|
||||
},
|
||||
async nextTask(taskMedicalReviewId) {
|
||||
|
||||
@@ -13,9 +13,13 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 受试者编号 -->
|
||||
<el-form-item :label="$t('trials:readTask:table:subjectCode')">
|
||||
<el-form-item v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0" :label="$t('trials:readTask:table:subjectCode')">
|
||||
<el-input v-model="searchData.SubjectCode" style="width:130px;" clearable />
|
||||
</el-form-item>
|
||||
<!-- 任务名称 -->
|
||||
<el-form-item :label="$t('trials:readTask:table:blindName')">
|
||||
<el-input v-model="searchData.TaskBlindName" style="width:130px;" clearable />
|
||||
</el-form-item>
|
||||
<!-- 任务状态 -->
|
||||
<el-form-item style="margin-bottom:10px" :label="$t('trials:readTask:table:taskState')">
|
||||
<el-select v-model="searchData.TaskState" clearable style="width:120px;">
|
||||
@@ -70,7 +74,7 @@
|
||||
show-overflow-tooltip
|
||||
/> -->
|
||||
<!-- 受试者编号 -->
|
||||
<el-table-column prop="SubjectCode" min-width="100" :label="$t('trials:readTask:table:subjectCode')"
|
||||
<el-table-column v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0" prop="SubjectCode" min-width="100" :label="$t('trials:readTask:table:subjectCode')"
|
||||
sortable="custom" show-overflow-tooltip />
|
||||
<!-- 盲态任务标识 -->
|
||||
<el-table-column prop="TaskBlindName" min-width="100" :label="$t('trials:readTask:table:blindName')"
|
||||
@@ -149,7 +153,7 @@
|
||||
scope.row.ReReadingApplyState) }}</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('common:action:action')" width="250" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="200" >
|
||||
<template slot-scope="scope">
|
||||
<!-- 查看 -->
|
||||
<el-button circle :title="$t('trials:readTask:button:view')" icon="el-icon-view"
|
||||
@@ -177,7 +181,8 @@
|
||||
custom-class="base-dialog-wrapper">
|
||||
<el-form ref="reasonForm" :rules="rules" :model="ApplyforReasonForm" class="demo-ruleForm" size="small"
|
||||
label-width="380px">
|
||||
<p>{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskBlindName) }}</p>
|
||||
<p v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0">{{ $t('trials:readTask:applyReread:title').replace('xxx', rowData.SubjectCode).replace('yyy', rowData.TaskBlindName) }}</p>
|
||||
<p v-else>{{ $t('trials:readTask:applyReread:title2').replace('yyy', rowData.TaskBlindName) }}</p>
|
||||
<!-- 申请原因 -->
|
||||
<el-divider content-position="left">{{ $t('trials:readTask:title:applyReason') }}</el-divider>
|
||||
<!-- 申请原因 -->
|
||||
@@ -209,7 +214,7 @@
|
||||
</el-form-item>
|
||||
<!-- 是否复制阅片表单 -->
|
||||
<el-form-item :label="$t('trials:readTask:title:IsCopyLesionAnswer')"
|
||||
v-if="ApplyforReasonForm.IsCopyOrigenalForms && isTumor && rowData.ReadingCategory === 1" prop="IsCopyFollowForms" :rules="[
|
||||
v-if="ApplyforReasonForm.IsCopyOrigenalForms && rowData.ReadingCategory === 1 && otherInfo.IsReadingTaskViewInOrder === 1" prop="IsCopyFollowForms" :rules="[
|
||||
{ required: true, message: $t('common:ruleMessage:select') },
|
||||
]">
|
||||
<el-radio-group v-model="ApplyforReasonForm.IsCopyFollowForms">
|
||||
@@ -229,7 +234,7 @@
|
||||
<el-table-column prop="TrialSiteCode" :label="$t('trials:readTask:table:siteCode')" min-width="100"
|
||||
show-overflow-tooltip />
|
||||
<!-- 受试者编号 -->
|
||||
<el-table-column prop="SubjectCode" :label="$t('trials:readTask:table:subjectCode')" min-width="120"
|
||||
<el-table-column v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0" prop="SubjectCode" :label="$t('trials:readTask:table:subjectCode')" min-width="120"
|
||||
show-overflow-tooltip />
|
||||
<!-- <el-table-column
|
||||
prop="VisitTaskNum"
|
||||
@@ -331,6 +336,7 @@ import { openWindow } from "@/utils/splitScreen";
|
||||
const searchDataDefault = () => {
|
||||
return {
|
||||
SubjectCode: '',
|
||||
TaskBlindName: '',
|
||||
SortField: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
@@ -366,12 +372,14 @@ export default {
|
||||
},
|
||||
trialCriterionList: [],
|
||||
TrialReadingCriterionId: '0',
|
||||
openWindow: null
|
||||
openWindow: null,
|
||||
otherInfo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
TrialReadingCriterionId(v) {
|
||||
if (v) {
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
@@ -413,6 +421,7 @@ export default {
|
||||
getIRHaveReadTaskList(this.searchData).then(res => {
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
this.otherInfo = res.OtherInfo
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
@@ -482,7 +491,7 @@ export default {
|
||||
if (!valid) return
|
||||
this.loading = true
|
||||
this.btnLoading = true
|
||||
if (!this.ApplyforReasonForm.IsCopyOrigenalForms || !this.isTumor) {
|
||||
if (!this.ApplyforReasonForm.IsCopyOrigenalForms) {
|
||||
this.ApplyforReasonForm.IsCopyFollowForms = false
|
||||
}
|
||||
var params = {
|
||||
@@ -496,6 +505,7 @@ export default {
|
||||
// IsCopyLesionAnswer: this.ApplyforReasonForm.IsCopyOrigenalForms,
|
||||
RequestReReadingReason: this.ApplyforReasonForm.Type === 2 ? this.ApplyforReasonForm.RequestReReadingReason : this.$t('trials:readTask:option:errorRecords') // '阅片记录错误'
|
||||
}
|
||||
console.log(params)
|
||||
applyReReading(params).then(res => {
|
||||
this.loading = false
|
||||
this.btnLoading = false
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
{{ scope.row.SuggesteFinishedTime.split(':')[0] + ':00:00' }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('common:action:action')" width="250" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="250" >
|
||||
<template slot-scope="scope">
|
||||
<!-- 阅片 -->
|
||||
<el-button :disabled="scope.row.ExistReadingApply" circle :title="scope.row.ExistReadingApply
|
||||
@@ -234,6 +234,7 @@ export default {
|
||||
watch: {
|
||||
TrialReadingCriterionId(v) {
|
||||
if (v) {
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
}
|
||||
},
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 受试者编号 -->
|
||||
<el-form-item :label="$t('trials:rereadTask:table:subjectCode')">
|
||||
<el-form-item v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0" :label="$t('trials:rereadTask:table:subjectCode')">
|
||||
<el-input v-model="searchData.SubjectCode" style="width:100px;" />
|
||||
</el-form-item>
|
||||
<!-- <el-form-item style="margin-bottom:10px" label="访视/阅片期名称">
|
||||
@@ -45,14 +45,14 @@
|
||||
clearable
|
||||
/>
|
||||
</el-form-item> -->
|
||||
<!-- 任务编号 -->
|
||||
<!-- <el-form-item :label="$t('trials:rereadTask:table:taskCode')">
|
||||
<!-- 任务名称 -->
|
||||
<el-form-item :label="$t('trials:rereadTask:table:taskBlindName')">
|
||||
<el-input
|
||||
v-model="searchData.TaskCode"
|
||||
v-model="searchData.TaskBlindName"
|
||||
style="width:130px;"
|
||||
clearable
|
||||
/>
|
||||
</el-form-item> -->
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('trials:rereadTask:table:taskState')">
|
||||
<el-select v-model="searchData.TaskState" clearable style="width:120px;">
|
||||
<el-option v-for="i of $d.TaskState" :key="'TaskState' + i.label" :value="i.value" :label="i.label" />
|
||||
@@ -121,6 +121,7 @@
|
||||
/>
|
||||
<!-- 受试者编号 -->
|
||||
<el-table-column
|
||||
v-if="otherInfo && otherInfo.IsReadingTaskViewInOrder !== 0"
|
||||
prop="OriginalReReadingTask.SubjectCode"
|
||||
min-width="90"
|
||||
:label="$t('trials:rereadTask:table:subjectCode')"
|
||||
@@ -303,6 +304,7 @@ const searchDataDefault = () => {
|
||||
return {
|
||||
IsUrgent: null,
|
||||
SubjectCode: '',
|
||||
TaskBlindName: '',
|
||||
TaskCode: '',
|
||||
PageIndex: 1,
|
||||
PageSize: 20,
|
||||
@@ -330,12 +332,14 @@ export default {
|
||||
},
|
||||
ConfirmReReadingVisible: false,
|
||||
trialCriterionList: [],
|
||||
TrialReadingCriterionId: '0'
|
||||
TrialReadingCriterionId: '0',
|
||||
otherInfo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
TrialReadingCriterionId(v) {
|
||||
if (v) {
|
||||
this.searchData = searchDataDefault()
|
||||
this.getList()
|
||||
}
|
||||
}
|
||||
@@ -373,6 +377,7 @@ export default {
|
||||
getIRReReadingTaskList(this.searchData).then(res => {
|
||||
this.list = res.Result.CurrentPageData
|
||||
this.total = res.Result.TotalCount
|
||||
this.otherInfo = res.OtherInfo
|
||||
this.loading = false
|
||||
}).catch(() => { this.loading = false })
|
||||
},
|
||||
|
||||
@@ -192,8 +192,8 @@
|
||||
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
|
||||
@click.stop="viewCD(v.taskInfo.VisitTaskId)" />
|
||||
</div>
|
||||
<h2 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo" class="subject-info">
|
||||
{{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
|
||||
<h2 class="subject-info">
|
||||
{{ taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo ? taskInfo.SubjectCode + ' ' + v.taskInfo.TaskBlindName : v.taskInfo.TaskBlindName }}
|
||||
</h2>
|
||||
<div v-if="v.currentFileName">{{ v.currentFileName }}</div>
|
||||
</div>
|
||||
|
||||
@@ -171,6 +171,21 @@ export default {
|
||||
document.addEventListener("click", this.foo);
|
||||
},
|
||||
methods: {
|
||||
setDefaultRelatedStudyInfo(visitTaskInfo) {
|
||||
if (!visitTaskInfo) return
|
||||
const studyList = visitTaskInfo.StudyList || []
|
||||
if (studyList.length === 0) return
|
||||
const firstStudy = studyList[0]
|
||||
const fileList = firstStudy.NoneDicomStudyFileList || []
|
||||
if (fileList.length === 0) return
|
||||
this.relatedStudyInfo = {
|
||||
fileInfo: fileList[0],
|
||||
visitTaskInfo,
|
||||
fileList,
|
||||
fileIndex: 0,
|
||||
studyId: firstStudy.Id
|
||||
}
|
||||
},
|
||||
handleReadingChart(row) {
|
||||
let { e, data } = row
|
||||
let obj = Object.assign({}, data)
|
||||
@@ -236,7 +251,7 @@ export default {
|
||||
return i
|
||||
})
|
||||
this.$set(this.visitTaskList[taskIdx], 'Annotations', annotations)
|
||||
this.$refs[visitTaskId][0].initCurrentMaredFiles()
|
||||
this.$refs[visitTaskId][0].initCurrentMaredFiles(annotations)
|
||||
this.$refs.fileViewer.resetAnnotations({ annotations, visitTaskId })
|
||||
},
|
||||
setReadingTaskState(state) {
|
||||
@@ -272,6 +287,9 @@ export default {
|
||||
const idx = res.Result.findIndex(i => i.IsCurrentTask)
|
||||
if (idx > -1) {
|
||||
await this.setActiveTaskVisitId(res.Result[idx].VisitTaskId)
|
||||
if (this.taskInfo.IsReadingTaskViewInOrder === 0) {
|
||||
this.setDefaultRelatedStudyInfo(this.visitTaskList[idx])
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
this.$refs[res.Result[idx].VisitTaskId][0].setInitActiveFile()
|
||||
})
|
||||
@@ -282,23 +300,15 @@ export default {
|
||||
if (i > -1) {
|
||||
await this.getReadingImageFile(res.Result[i].VisitTaskId, i)
|
||||
await this.getAnnotations(res.Result[i].VisitTaskId, i)
|
||||
const studyList = this.visitTaskList[i].StudyList
|
||||
if (studyList.length > 0) {
|
||||
const fileInfo = studyList[0].NoneDicomStudyFileList[0]
|
||||
this.relatedStudyInfo = { fileInfo, visitTaskInfo: this.visitTaskList[i], fileList: studyList[0].NoneDicomStudyFileList, fileIndex: 0, studyId: studyList[0].Id }
|
||||
if (!this.selectArr.includes(res.Result[i].VisitTaskId)) {
|
||||
this.selectArr.push(res.Result[i].VisitTaskId)
|
||||
}
|
||||
this.setDefaultRelatedStudyInfo(this.visitTaskList[i])
|
||||
if (!this.selectArr.includes(res.Result[i].VisitTaskId)) {
|
||||
this.selectArr.push(res.Result[i].VisitTaskId)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.taskInfo.IsReadingTaskViewInOrder === 2) {
|
||||
// 受试者内随机
|
||||
const studyList = this.visitTaskList[idx].StudyList
|
||||
if (studyList.length > 0) {
|
||||
const fileInfo = studyList[0].NoneDicomStudyFileList[0]
|
||||
this.relatedStudyInfo = { fileInfo, visitTaskInfo: this.visitTaskList[idx], fileList: studyList[0].NoneDicomStudyFileList, fileIndex: 0, studyId: studyList[0].Id }
|
||||
}
|
||||
this.setDefaultRelatedStudyInfo(this.visitTaskList[idx])
|
||||
}
|
||||
if (this.readingTaskState < 2) {
|
||||
this.$refs[res.Result[idx].VisitTaskId][0].initCurrentMaredFiles()
|
||||
|
||||
@@ -4,7 +4,10 @@
|
||||
<div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="taskInfo.SubjectCode">
|
||||
{{ taskInfo.SubjectCode }}
|
||||
</div>
|
||||
<div v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo" :title="visitTaskInfo.TaskBlindName">
|
||||
<div :title="visitTaskInfo.TaskBlindName">
|
||||
<span v-if="taskInfo && !taskInfo.IsReadingShowSubjectInfo">
|
||||
{{ $t('trials:reading:title:taskName') }}
|
||||
</span>
|
||||
{{ visitTaskInfo.TaskBlindName }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -15,12 +18,13 @@
|
||||
<div v-if="!study.IsCriticalSequence" class="dicom-desc">
|
||||
<!-- <div v-if="taskInfo && taskInfo.IsShowStudyName">{{ study.StudyName }}</div> -->
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
<span :title="study.CodeView">{{ study.CodeView }}</span>
|
||||
<span v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder !== 0" :title="study.CodeView">{{
|
||||
study.CodeView }}</span>
|
||||
<span v-if="taskInfo && taskInfo.IsShowStudyName" :title="study.StudyName" style="margin-left: 5px;">{{
|
||||
study.StudyName }}</span>
|
||||
</div>
|
||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
||||
<span :title="study.BodyPart">{{ getBodyPart(study.BodyPart, study.BodyPartForEditOther) }}</span>
|
||||
<span :title="study.DisplayBodyPart">{{ study.DisplayBodyPart }}</span>
|
||||
<span style="margin-left: 5px;" :title="study.Modality">{{ study.Modality }}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -91,21 +95,48 @@ export default {
|
||||
},
|
||||
async mounted() {
|
||||
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
|
||||
this.studyList = this.visitTaskInfo.StudyList
|
||||
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
|
||||
this.studyList = this.decorateStudyList(this.visitTaskInfo.StudyList || [])
|
||||
this.initCurrentMaredFiles(this.visitTaskInfo.Annotations)
|
||||
if (this.studyList.length === 0) return
|
||||
this.$nextTick(() => {
|
||||
this.activeStudy(this.studyList[0].Id)
|
||||
})
|
||||
this.BodyPart.Bodypart = await this.$getBodyPart(this.$route.query.trialId)
|
||||
},
|
||||
watch: {
|
||||
activeFileIndex() {
|
||||
this.scrollElementToTop(this.$refs[`noneDicomRef_${this.activeFileIndex}`][0], {
|
||||
offset: 50
|
||||
})
|
||||
if (this.$refs[`noneDicomRef_${this.activeFileIndex}`]) {
|
||||
this.scrollElementToTop(this.$refs[`noneDicomRef_${this.activeFileIndex}`][0], {
|
||||
offset: 50
|
||||
})
|
||||
}
|
||||
},
|
||||
'visitTaskInfo.Annotations': {
|
||||
handler(annotations) {
|
||||
this.initCurrentMaredFiles(annotations)
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
buildCurrentMarkedFiles(annotations = []) {
|
||||
return annotations.reduce((result, item) => {
|
||||
const fileId = item?.NoneDicomFileId
|
||||
if (!fileId) return result
|
||||
if (!Object.hasOwn(result, fileId)) {
|
||||
result[fileId] = { count: 1 }
|
||||
} else {
|
||||
result[fileId].count++
|
||||
}
|
||||
return result
|
||||
}, {})
|
||||
},
|
||||
decorateStudyList(studyList = []) {
|
||||
return studyList.map(study => ({
|
||||
...study,
|
||||
DisplayBodyPart: this.getBodyPart(study.BodyPart, study.BodyPartForEditOther)
|
||||
}))
|
||||
},
|
||||
scrollElementToTop(element, options = {}) {
|
||||
const container = this.$refs['studyBox_ps']
|
||||
if (!container || !element) return
|
||||
@@ -122,6 +153,7 @@ export default {
|
||||
},
|
||||
getBodyPart(bodyPart, other) {
|
||||
if (!bodyPart && !other) return ''
|
||||
if (!bodyPart) return other || ''
|
||||
var separator = ','
|
||||
if (bodyPart.indexOf('|') > -1) {
|
||||
separator = '|'
|
||||
@@ -142,6 +174,9 @@ export default {
|
||||
},
|
||||
// 设置初始化激活文件
|
||||
setInitActiveFile() {
|
||||
if (this.studyList.length === 0) {
|
||||
this.studyList = this.decorateStudyList(this.visitTaskInfo.StudyList || [])
|
||||
}
|
||||
if (this.studyList.length === 0) return
|
||||
this.$nextTick(() => {
|
||||
this.activeStudy(this.studyList[0].Id)
|
||||
@@ -172,8 +207,9 @@ export default {
|
||||
this.activeFileIndex = fIndex
|
||||
},
|
||||
activeStudy(id) {
|
||||
if (this.activeNames.indexOf(id) > -1) return
|
||||
this.activeNames.push(id)
|
||||
const studyId = `${id}`
|
||||
if (this.activeNames.indexOf(studyId) > -1) return
|
||||
this.activeNames.push(studyId)
|
||||
},
|
||||
handleChange(v) {
|
||||
console.log(v)
|
||||
@@ -187,6 +223,9 @@ export default {
|
||||
if (type === 'remove') {
|
||||
if (Object.hasOwn(this.currentMarkedFiles, fileId)) {
|
||||
this.currentMarkedFiles[fileId].count--
|
||||
if (this.currentMarkedFiles[fileId].count <= 0) {
|
||||
this.$delete(this.currentMarkedFiles, fileId)
|
||||
}
|
||||
}
|
||||
} else if (type === 'add') {
|
||||
if (!Object.hasOwn(this.currentMarkedFiles, fileId)) {
|
||||
@@ -197,15 +236,8 @@ export default {
|
||||
|
||||
}
|
||||
},
|
||||
initCurrentMaredFiles() {
|
||||
this.currentMarkedFiles = {}
|
||||
this.visitTaskInfo.Annotations.map(i => {
|
||||
if (!Object.hasOwn(this.currentMarkedFiles, i.NoneDicomFileId)) {
|
||||
this.$set(this.currentMarkedFiles, i.NoneDicomFileId, { count: 1 })
|
||||
} else {
|
||||
this.currentMarkedFiles[i.NoneDicomFileId].count++
|
||||
}
|
||||
})
|
||||
initCurrentMaredFiles(annotations = this.visitTaskInfo.Annotations || []) {
|
||||
this.currentMarkedFiles = this.buildCurrentMarkedFiles(annotations)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -227,7 +259,13 @@ export default {
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #4c4c4c;
|
||||
height: 50px;
|
||||
min-height: 50px;
|
||||
height: auto;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.dicom-desc {
|
||||
|
||||
@@ -222,6 +222,9 @@
|
||||
form.IseCRFShowInDicomReading = false
|
||||
} else {
|
||||
form.ReadingTaskViewEnum = 2
|
||||
form.IsReadingShowSubjectInfo = false
|
||||
form.IsReadingShowPreviousResults = false
|
||||
form.IseCRFShowInDicomReading = true
|
||||
}
|
||||
if (CriterionType !== 10 && (v === 0 || v === 2)) {
|
||||
form.IsReadingPeriod = false
|
||||
@@ -279,7 +282,7 @@
|
||||
" prop="IsReadingShowSubjectInfo">
|
||||
<el-radio-group v-model="form.IsReadingShowSubjectInfo" :disabled="isConfirm ||
|
||||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
|
||||
!!form.IsReadingTaskViewInOrder
|
||||
form.IsReadingTaskViewInOrder >= 0
|
||||
">
|
||||
<el-radio v-for="item of $d.YesOrNo" :key="'IsReadingShowSubjectInfo' + item.value" :label="item.value">
|
||||
{{ item.label }}
|
||||
@@ -293,7 +296,7 @@
|
||||
" prop="IsReadingShowPreviousResults">
|
||||
<el-radio-group v-model="form.IsReadingShowPreviousResults" :disabled="isConfirm ||
|
||||
!hasPermi(['trials:trials-panel:setting:reading-unit:edit']) ||
|
||||
!!form.IsReadingTaskViewInOrder
|
||||
form.IsReadingTaskViewInOrder >= 0
|
||||
" @change="
|
||||
(v) => {
|
||||
if (!v) {
|
||||
|
||||
@@ -13,10 +13,13 @@
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<el-table :data="tableList" border style="width: 100%">
|
||||
<el-table-column v-for="item in tableKey" :key="item.key" :prop="item.key" :label="item.title">
|
||||
<el-table-column v-for="(item, index) in tableKey" :key="item.key" :prop="item.key" :label="item.title">
|
||||
<template slot-scope="scope">
|
||||
<span :class="{ IsHighlight: scope.row.IsHighlight.includes(item.key) }">{{ scope.row[item.key]
|
||||
}}</span>
|
||||
<el-button icon="el-icon-view" circle v-if="index > 0 && scope.row[item.key]" size="mini"
|
||||
style="margin-left: 5px;" :title="$t('common:button:view')"
|
||||
@click="lookReadingResults(scope.row.VisitTaskId[item.key])"></el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -49,6 +52,7 @@ import {
|
||||
} from '@/api/trials'
|
||||
import * as echarts from 'echarts/core';
|
||||
import { LineChart } from 'echarts/charts';
|
||||
import { getToken } from '@/utils/auth'
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
@@ -108,13 +112,33 @@ export default {
|
||||
tableKey: [],
|
||||
tableList: [],
|
||||
R1ChartList: [],
|
||||
R2ChartList: []
|
||||
R2ChartList: [],
|
||||
openWindow: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getTrialCriterionList()
|
||||
},
|
||||
methods: {
|
||||
// 查看阅片结果
|
||||
lookReadingResults(id) {
|
||||
if (this.openWindow) {
|
||||
this.openWindow.close()
|
||||
}
|
||||
var token = getToken()
|
||||
var path = null
|
||||
let trialCriterion = this.trialCriterionList.find(item => item.TrialReadingCriterionId === this.TrialReadingCriterionId)
|
||||
let trialId = this.$route.query.trialId
|
||||
if (trialCriterion.ReadingTool === 0 || trialCriterion.ReadingTool === 2 || trialCriterion.ReadingTool === 3) {
|
||||
path = `/readingDicoms?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.data.Code}&subjectId=${this.data.Id}&visitTaskId=${id}&isReadingTaskViewInOrder=${trialCriterion.IsReadingTaskViewInOrder}&criterionType=${trialCriterion.CriterionType}&readingTool=${trialCriterion.ReadingTool}&TokenKey=${token}`
|
||||
} else {
|
||||
path = `/noneDicomReading?TrialReadingCriterionId=${this.TrialReadingCriterionId}&trialId=${trialId}&subjectCode=${this.data.Code}&subjectId=${this.data.Id}&visitTaskId=${id}&isReadingTaskViewInOrder=${trialCriterion.IsReadingTaskViewInOrder}&criterionType=${trialCriterion.CriterionType}&readingTool=${trialCriterion.ReadingTool}&TokenKey=${token}`
|
||||
}
|
||||
// const routeData = this.$router.resolve({
|
||||
// path: `/readingPage?subjectId=${row.SubjectId}&trialId=${row.TrialId}&visitTaskId=${row.Id}&TokenKey=${token}`
|
||||
// })
|
||||
this.openWindow = window.open(path, '_blank')
|
||||
},
|
||||
handleChange(v) {
|
||||
this.getList()
|
||||
},
|
||||
@@ -159,12 +183,14 @@ export default {
|
||||
this.tableList = []
|
||||
if (Evaluation[1] && Evaluation[1].length > 0) {
|
||||
let obj = {
|
||||
IsHighlight: []
|
||||
IsHighlight: [],
|
||||
VisitTaskId: {}
|
||||
}
|
||||
this.tableKey.forEach((item, index) => {
|
||||
if (index === 0) {
|
||||
obj[item.key] = 'R1'
|
||||
} else {
|
||||
obj.VisitTaskId[item.key] = Evaluation[1][index - 1].VisitTaskId
|
||||
obj[item.key] = Evaluation[1][index - 1].DictionaryCode ? this.$fd(Evaluation[1][index - 1].DictionaryCode, parseFloat(Evaluation[1][index - 1].Value)) : Evaluation[1][index - 1].Value
|
||||
if (Evaluation[1][index - 1].IsHighlight) {
|
||||
obj.IsHighlight.push(item.key)
|
||||
@@ -176,13 +202,17 @@ export default {
|
||||
}
|
||||
if (Evaluation[2] && Evaluation[2].length > 0) {
|
||||
let obj = {
|
||||
IsHighlight: []
|
||||
IsHighlight: [],
|
||||
VisitTaskId: {}
|
||||
}
|
||||
this.tableKey.forEach((item, index) => {
|
||||
obj[item.key] = index === 0 ? 'R2' : Evaluation[2][index - 1].DictionaryCode ? this.$fd(Evaluation[2][index - 1].DictionaryCode, parseFloat(Evaluation[2][index - 1].Value)) : Evaluation[2][index - 1].Value
|
||||
if (index > 0 && Evaluation[2][index - 1].IsHighlight) {
|
||||
obj.IsHighlight.push(item.key)
|
||||
}
|
||||
if (index > 0) {
|
||||
obj.VisitTaskId[item.key] = Evaluation[2][index - 1].VisitTaskId
|
||||
}
|
||||
})
|
||||
this.tableList.push(obj)
|
||||
}
|
||||
@@ -331,7 +361,7 @@ export default {
|
||||
}
|
||||
|
||||
.IsHighlight {
|
||||
color: red;
|
||||
color: #00f;
|
||||
}
|
||||
|
||||
.chartBox {
|
||||
|
||||
+41
-10
@@ -9,10 +9,10 @@
|
||||
</el-radio-group>
|
||||
</el-form-item>
|
||||
<!-- Out Visit Date -->
|
||||
<el-form-item v-if="form.Status == 2" :label="$t('trials:subject:table:outVisitDate')" prop="VisitOverTime">
|
||||
<!-- <el-form-item v-if="form.Status == 2" :label="$t('trials:subject:table:outVisitDate')" prop="VisitOverTime">
|
||||
<el-date-picker v-model="form.VisitOverTime" type="date" :picker-options="pickerOption"
|
||||
value-format="yyyy-MM-dd" format="yyyy-MM-dd" />
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
<!-- 末次访视 -->
|
||||
<el-form-item v-if="form.Status === 2" :label="$t('trials:subject:table:finalSubjectVisit')"
|
||||
prop="FinalSubjectVisitId">
|
||||
@@ -21,14 +21,43 @@
|
||||
<el-option v-for="item in subjectVisitOptions" :key="item.Id" :label="item.VisitName" :value="item.Id" />
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
<!-- 访视中原因-->
|
||||
<el-form-item
|
||||
v-if="(form.Status < data.Status && form.Status === 1) || (form.BackReason)"
|
||||
:label="$t('trials:subject:table:outVisitReason')"
|
||||
prop="BackReason"
|
||||
:rules="[
|
||||
{ required: this.form.Status < this.data.Status, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500`, trigger: ['blur'] }
|
||||
]"
|
||||
>
|
||||
<el-input v-model="form.BackReason" type="textarea" autosize />
|
||||
</el-form-item>
|
||||
<!-- 结束访视的原因 -->
|
||||
<el-form-item v-if="form.Status === 2" :label="$t('trials:subject:table:outVisitReason')" prop="Reason">
|
||||
<el-form-item
|
||||
v-if="form.Status === 2"
|
||||
:label="$t('trials:subject:table:outVisitReason')"
|
||||
prop="Reason"
|
||||
:rules="[
|
||||
{ required: this.form.Status < this.data.Status, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500`, trigger: ['blur'] }
|
||||
]"
|
||||
>
|
||||
<el-input v-model="form.Reason" type="textarea" autosize />
|
||||
</el-form-item>
|
||||
<!-- 访视中止的原因 -->
|
||||
<el-form-item v-if="form.Status === 3" :label="$t('trials:subject:table:outVisitReason')" prop="SuspendReason">
|
||||
<el-form-item
|
||||
v-if="form.Status === 3"
|
||||
:label="$t('trials:subject:table:outVisitReason')"
|
||||
prop="SuspendReason"
|
||||
:rules="[
|
||||
{ required: this.form.Status < this.data.Status, message: this.$t('common:ruleMessage:specify'), trigger: ['blur'] },
|
||||
{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500`, trigger: ['blur'] }
|
||||
]"
|
||||
>
|
||||
<el-input v-model="form.SuspendReason" type="textarea" autosize />
|
||||
</el-form-item>
|
||||
|
||||
</div>
|
||||
<div class="base-dialog-footer" style="text-align:right;margin-top:10px;">
|
||||
<el-form-item style="text-align:right;">
|
||||
@@ -61,16 +90,16 @@ export default {
|
||||
Status: 1,
|
||||
OutEnrollmentTime: '',
|
||||
Reason: '',
|
||||
VisitOverTime: '',
|
||||
// VisitOverTime: '',
|
||||
FinalSubjectVisitId: '',
|
||||
SuspendReason: ''
|
||||
SuspendReason: '',
|
||||
BackReason: ''
|
||||
},
|
||||
rules: {
|
||||
OutEnrollmentTime: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }],
|
||||
FinalSubjectVisitId: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }],
|
||||
Reason: [{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500` }],
|
||||
SuspendReason: [{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500` }],
|
||||
VisitOverTime: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }]
|
||||
// SuspendReason: [{ max: 500, message: `${this.$t('common:ruleMessage:maxLength')} 500` }],
|
||||
// VisitOverTime: [{ required: true, message: this.$t('common:ruleMessage:select'), trigger: ['blur'] }]
|
||||
},
|
||||
pickerOption: {
|
||||
disabledDate: time => {
|
||||
@@ -91,6 +120,8 @@ export default {
|
||||
methods: {
|
||||
handleChange() {
|
||||
if (this.form.Status !== 3) this.form.SuspendReason = ''
|
||||
if (this.form.Status !== 2) this.form.Reason = ''
|
||||
if (this.form.Status !== 1) this.form.BackReason = ''
|
||||
},
|
||||
async initForm() {
|
||||
this.loading = true
|
||||
@@ -116,7 +147,7 @@ export default {
|
||||
this.form.TrialId = this.trialId
|
||||
this.form.TrialSiteId = this.data.TrialSiteId
|
||||
if (this.form.Status !== 2) {
|
||||
this.form.VisitOverTime = ''
|
||||
// this.form.VisitOverTime = ''
|
||||
this.form.FinalSubjectVisitId = ''
|
||||
}
|
||||
updateSubjectStatus(this.form).then(res => {
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
<template>
|
||||
<div class="json-editor" v-loading="loading">
|
||||
<div class="header">
|
||||
<!-- <span class="title">JSON 编辑</span> -->
|
||||
<el-button type="primary" size="mini" icon="el-icon-check" @click="save">
|
||||
{{ $t('common:button:save') }}
|
||||
</el-button>
|
||||
</div>
|
||||
<div class="json">
|
||||
<json-node
|
||||
:node-key="'root'"
|
||||
:node-value="jsonData"
|
||||
:is-root="true"
|
||||
@update="handleUpdate"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getInspectionById, setJsonDetail } from '@/api/trials'
|
||||
import JsonNode from './JsonNode.vue'
|
||||
|
||||
export default {
|
||||
name: 'JsonEditor',
|
||||
components: { JsonNode },
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: false,
|
||||
jsonData: {}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.getJsonData()
|
||||
},
|
||||
methods: {
|
||||
handleUpdate({ path, value }) {
|
||||
const target = this.getTarget(path.slice(0, -1))
|
||||
this.$set(target, path[path.length - 1], value)
|
||||
},
|
||||
getTarget(path) {
|
||||
let t = this.jsonData
|
||||
path.forEach(k => { t = t[k] })
|
||||
return t
|
||||
},
|
||||
parseValue(val) {
|
||||
if (typeof val === 'string') {
|
||||
try {
|
||||
const parsed = JSON.parse(val)
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
return JSON.parse(JSON.stringify(parsed))
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(e.message)
|
||||
}
|
||||
return {}
|
||||
}
|
||||
return val ? JSON.parse(JSON.stringify(val)) : {}
|
||||
},
|
||||
async getJsonData() {
|
||||
try {
|
||||
this.loading = true
|
||||
const res = await getInspectionById({ id: this.id })
|
||||
if (res.IsSuccess) {
|
||||
this.jsonData = this.parseValue(res.Result.JsonDetail)
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
isValidJsonObject(obj) {
|
||||
if (obj === null || typeof obj !== 'object') return false
|
||||
try {
|
||||
JSON.stringify(obj)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.warn(e.message)
|
||||
return false
|
||||
}
|
||||
},
|
||||
safeClone(obj) {
|
||||
if (this.isValidJsonObject(obj)) {
|
||||
return JSON.parse(JSON.stringify(obj))
|
||||
}
|
||||
return {}
|
||||
},
|
||||
async save() {
|
||||
try {
|
||||
this.loading = true
|
||||
const result = this.safeClone(this.jsonData)
|
||||
const res = await setJsonDetail({ id: this.id, jsonDetail: JSON.stringify(result) })
|
||||
if (res.IsSuccess) {
|
||||
this.$emit('getList')
|
||||
this.$emit('close')
|
||||
this.$message.success(this.$t('common:message:savedSuccessfully'))
|
||||
}
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.json-editor {
|
||||
font-family: Consolas, Monaco, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 2;
|
||||
padding: 12px;
|
||||
background: #fafafa;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.header {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
}
|
||||
.title {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
}
|
||||
.json {
|
||||
max-height: 50vh;
|
||||
overflow: auto;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,136 @@
|
||||
<template>
|
||||
<div class="node" :style="{ paddingLeft: depth * 20 + 'px' }">
|
||||
<span v-if="!isRoot" class="key">
|
||||
{{ isArray ? `[${nodeKey}]` : `"${nodeKey}"` }}:
|
||||
</span>
|
||||
|
||||
<!-- 对象 -->
|
||||
<template v-if="isObject">
|
||||
<span class="bracket">{</span>
|
||||
<div class="children">
|
||||
<json-node
|
||||
v-for="(v, k) in nodeValue"
|
||||
:key="k"
|
||||
:node-key="k"
|
||||
:node-value="v"
|
||||
:depth="depth + 1"
|
||||
:parent-path="currentPath"
|
||||
@update="$emit('update', $event)"
|
||||
/>
|
||||
</div>
|
||||
<span class="bracket">}</span>
|
||||
</template>
|
||||
|
||||
<!-- 数组 -->
|
||||
<template v-else-if="isArray">
|
||||
<span class="bracket">[</span>
|
||||
<div class="children">
|
||||
<json-node
|
||||
v-for="(item, i) in nodeValue"
|
||||
:key="i"
|
||||
:node-key="i"
|
||||
:node-value="item"
|
||||
:depth="depth + 1"
|
||||
:parent-path="currentPath"
|
||||
@update="$emit('update', $event)"
|
||||
/>
|
||||
</div>
|
||||
<span class="bracket">]</span>
|
||||
</template>
|
||||
|
||||
<!-- 文本 -->
|
||||
<el-input
|
||||
v-else-if="valueType === 'string'"
|
||||
v-model="editVal"
|
||||
size="mini"
|
||||
style="width: 300px"
|
||||
@blur="emitUpdate"
|
||||
@keyup.enter.native="emitUpdate"
|
||||
/>
|
||||
|
||||
<!-- 数字 -->
|
||||
<el-input-number
|
||||
v-else-if="valueType === 'number'"
|
||||
v-model="editVal"
|
||||
size="mini"
|
||||
style="width: 140px"
|
||||
@blur="emitUpdate"
|
||||
/>
|
||||
|
||||
<!-- 布尔值 -->
|
||||
<el-switch
|
||||
v-else-if="valueType === 'boolean'"
|
||||
v-model="editVal"
|
||||
size="small"
|
||||
@change="emitUpdate"
|
||||
/>
|
||||
|
||||
<!-- null -->
|
||||
<el-tag v-else size="mini" type="info">null</el-tag>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'JsonNode',
|
||||
props: {
|
||||
nodeKey: [String, Number],
|
||||
nodeValue: [Object, Array, String, Number, Boolean],
|
||||
depth: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
isRoot: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
parentPath: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return { editVal: this.nodeValue }
|
||||
},
|
||||
computed: {
|
||||
isObject() {
|
||||
return this.nodeValue && typeof this.nodeValue === 'object' && !Array.isArray(this.nodeValue)
|
||||
},
|
||||
isArray() {
|
||||
return Array.isArray(this.nodeValue)
|
||||
},
|
||||
valueType() {
|
||||
if (this.nodeValue === null) return 'null'
|
||||
return typeof this.nodeValue
|
||||
},
|
||||
currentPath() {
|
||||
return this.isRoot ? [] : [...this.parentPath, this.nodeKey]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
nodeValue(v) { this.editVal = v }
|
||||
},
|
||||
methods: {
|
||||
emitUpdate() {
|
||||
this.$emit('update', { path: this.currentPath, value: this.editVal })
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.node {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
.key {
|
||||
color: #c7254e;
|
||||
margin-right: 4px;
|
||||
}
|
||||
.bracket {
|
||||
color: #e6a23c;
|
||||
font-weight: bold;
|
||||
}
|
||||
.children {
|
||||
padding-left: 4px;
|
||||
}
|
||||
</style>
|
||||
@@ -194,6 +194,9 @@
|
||||
<el-button type="text" @click="lookDetails(scope.row)">
|
||||
{{ $t('trials:auditRecord:action:detail') }}
|
||||
</el-button>
|
||||
<el-button type="text" @click="edit(scope.row)">
|
||||
{{ $t('common:button:edit') }}
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
@@ -622,6 +625,20 @@
|
||||
<!-- :src="openImageUrl"-->
|
||||
<!-- style="width: 50px;height: 50px; cursor:pointer">-->
|
||||
<!-- </div>-->
|
||||
<!-- <json-editor v-model="data" /> -->
|
||||
<el-dialog
|
||||
v-if="editDialogVisible"
|
||||
:visible.sync="editDialogVisible"
|
||||
:close-on-click-modal="false"
|
||||
:title="$t('common:button:edit') + `${$i18n.locale === 'zh' ? '(' + editRow.DescriptionCN + ')' : '( ' + editRow.Description + ' )'}`"
|
||||
width="720px"
|
||||
custom-class="base-dialog-wrapper">
|
||||
<json-editor
|
||||
:id="editRow.Id"
|
||||
@close="editDialogVisible = false"
|
||||
@getList="getList"
|
||||
/>
|
||||
</el-dialog>
|
||||
</template>
|
||||
</BaseContainer>
|
||||
</template>
|
||||
@@ -630,11 +647,12 @@
|
||||
import {
|
||||
getTrialSiteSelect,
|
||||
getTrialVisitStageSelect,
|
||||
getTrialCriterionList
|
||||
getTrialCriterionList,
|
||||
} from '@/api/trials'
|
||||
import { getInspectionList, getInspectionJsonDataList } from '@/api/trials/inspection'
|
||||
import { getFrontAuditConfigList, getAuditConfigChildList, getModuleTypeDescriptionList, setInspectionEnumValue, getModuleTypeList } from '@/api/dictionary/checkConfig'
|
||||
import Pagination from '@/components/Pagination'
|
||||
import JsonEditor from './components/JsonEditor'
|
||||
import BaseContainer from '@/components/BaseContainer'
|
||||
import BaseModel from '@/components/BaseModel'
|
||||
import { getToken } from '@/utils/auth'
|
||||
@@ -670,7 +688,7 @@ const searchDataDefault = () => {
|
||||
}
|
||||
}
|
||||
export default {
|
||||
components: { BaseContainer, Pagination, BaseModel },
|
||||
components: { BaseContainer, Pagination, JsonEditor, BaseModel },
|
||||
dicts: ['OptType', 'ModuleType', 'ChildrenType'],
|
||||
data() {
|
||||
|
||||
@@ -708,7 +726,10 @@ export default {
|
||||
imagesList: [],
|
||||
moduleTypeList: [],
|
||||
list2_total: 0,
|
||||
list2_searchData: {}
|
||||
list2_searchData: {},
|
||||
editDialogVisible: false,
|
||||
jsonData: null,
|
||||
editRow: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -1346,7 +1367,12 @@ export default {
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
}
|
||||
},
|
||||
edit(row) {
|
||||
this.editRow = Object.assign({}, row)
|
||||
this.editDialogVisible = true
|
||||
|
||||
},
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -105,6 +105,7 @@
|
||||
<el-button icon="el-icon-delete" :title="$t('trials:uploadedDicoms:action:delete')" circle
|
||||
:disabled="!isAfresh && data.SubmitState === 2 && data.SubmitTime && moment(data.SubmitTime).isAfter(moment(scope.row.UploadedTime))"
|
||||
@click="handleDeleteStudy(scope.row)" />
|
||||
<el-button icon="el-icon-upload2" title="上传" circle @click="upload(scope.row)" />
|
||||
<!-- <el-button-->
|
||||
<!-- icon="el-icon-toilet-paper"-->
|
||||
<!-- circle-->
|
||||
@@ -423,7 +424,8 @@
|
||||
<DicomPreview :uid="uid" :studyList="uploadQueues" />
|
||||
</el-dialog>
|
||||
<!--pet-ct临床数据上传-->
|
||||
<el-dialog v-if="petVisible" :show-close="true" :close-on-click-modal="false" :visible.sync="petVisible" append-to-body>
|
||||
<el-dialog v-if="petVisible" :show-close="true" :close-on-click-modal="false" :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>
|
||||
@@ -650,6 +652,7 @@ export default {
|
||||
BodyPart: {},
|
||||
|
||||
isClose: false,
|
||||
StudyInstanceUID: null
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -682,6 +685,10 @@ export default {
|
||||
this.OSSclient.close()
|
||||
},
|
||||
methods: {
|
||||
upload(row) {
|
||||
this.StudyInstanceUID = row.StudyInstanceUid
|
||||
this.$refs.pathClear.click()
|
||||
},
|
||||
handleDragover(e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
@@ -1144,7 +1151,7 @@ export default {
|
||||
var instanceItem = instanceList.find(function (item) {
|
||||
return item.instanceUid === instanceUid
|
||||
})
|
||||
if (!instanceItem) {
|
||||
if (!false) {
|
||||
var date = data.string('x00080023')
|
||||
var time = data.string('x00080033')
|
||||
var instanceTime = ''
|
||||
@@ -1274,11 +1281,12 @@ export default {
|
||||
verifyStudy() {
|
||||
this.btnLoading = true
|
||||
var studyList = []
|
||||
let scope = this
|
||||
this.selectArr.forEach((item) => {
|
||||
item.dicomInfo.uploadFileSize = 0
|
||||
if (!item.uploadState.selected) {
|
||||
studyList.push({
|
||||
studyInstanceUid: item.dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.StudyInstanceUID ? scope.StudyInstanceUID : item.dicomInfo.studyUid,
|
||||
studyDate: item.dicomInfo.studyTime,
|
||||
})
|
||||
}
|
||||
@@ -1293,6 +1301,8 @@ export default {
|
||||
batchVerifyStudyAllowUpload(param)
|
||||
.then(async (res) => {
|
||||
var messageArr = []
|
||||
res.Result = []
|
||||
console.log(res)
|
||||
res.Result.forEach((item) => {
|
||||
const i = this.uploadQueues.findIndex(
|
||||
(value) => value.dicomInfo.studyUid === item.StudyInstanceUid
|
||||
@@ -1475,8 +1485,21 @@ export default {
|
||||
})
|
||||
},
|
||||
// 上传影像并归档
|
||||
archiveStudy(index, config) {
|
||||
archiveStudy(index, config = {}) {
|
||||
var scope = this
|
||||
try {
|
||||
if (!config.AnonymizeFixedList) config.AnonymizeFixedList = []
|
||||
config.AnonymizeFixedList.push(
|
||||
{
|
||||
Element: '000D',
|
||||
Group: '0020',
|
||||
ReplaceValue: scope.StudyInstanceUID,
|
||||
Id: 'StudyInstanceUID'
|
||||
}
|
||||
)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
preArchiveDicomStudy({
|
||||
@@ -1506,7 +1529,7 @@ export default {
|
||||
let t = setInterval(() => {
|
||||
dicomUploadInProgress({
|
||||
trialId: scope.trialId,
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
}).then((res) => { })
|
||||
}, 5000)
|
||||
scope.myInterval.push(t)
|
||||
@@ -1531,7 +1554,7 @@ export default {
|
||||
dicomInfo.RadiopharmaceuticalStartTime,
|
||||
|
||||
studyId: dicomInfo.studyId,
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
studyTime: dicomInfo.studyTime,
|
||||
description: dicomInfo.description,
|
||||
seriesCount: dicomInfo.seriesNum,
|
||||
@@ -1572,14 +1595,149 @@ export default {
|
||||
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) {
|
||||
// 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,
|
||||
// SOPClassUID: o.SOPClassUID,
|
||||
// TransferSytaxUID: o.TransferSytaxUID,
|
||||
// MediaStorageSOPInstanceUID:
|
||||
// o.MediaStorageSOPInstanceUID,
|
||||
// MediaStorageSOPClassUID:
|
||||
// o.MediaStorageSOPClassUID,
|
||||
// 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,
|
||||
|
||||
// PhotometricInterpretation:
|
||||
// o.PhotometricInterpretation,
|
||||
// BitsAllocated: o.BitsAllocated,
|
||||
// PixelRepresentation: o.PixelRepresentation,
|
||||
// RescaleIntercept: o.RescaleIntercept,
|
||||
// RescaleSlope: o.RescaleSlope,
|
||||
// ImagePositionPatient: o.ImagePositionPatient,
|
||||
// ImageOrientationPatient:
|
||||
// o.ImageOrientationPatient,
|
||||
// SequenceOfUltrasoundRegions:
|
||||
// o.SequenceOfUltrasoundRegions,
|
||||
// FrameTime: o.FrameTime,
|
||||
// CorrectedImage: o.CorrectedImage,
|
||||
// Units: o.Units,
|
||||
// DecayCorrection: o.DecayCorrection,
|
||||
// EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
// })
|
||||
// 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
|
||||
console.log(o.file)
|
||||
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
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: o.file.name,
|
||||
fileSize: o.file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 1,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
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,
|
||||
{
|
||||
fileName: `${v.seriesUid}.jpg`,
|
||||
fileSize: blob.size,
|
||||
fileType: 'image/jpeg',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 2,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
if (seriesRes && seriesRes.url) {
|
||||
ImageResizePath = scope.$getObjectName(
|
||||
seriesRes.url
|
||||
)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (res && res.url) {
|
||||
instanceList.push({
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
seriesInstanceUid: v.seriesUid,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
@@ -1600,7 +1758,7 @@ export default {
|
||||
frameOfReferenceUID: o.frameOfReferenceUID,
|
||||
windowCenter: o.windowCenter,
|
||||
windowWidth: o.windowWidth,
|
||||
path: o.myPath,
|
||||
path: scope.$getObjectName(res.url),
|
||||
FileSize: o.FileSize,
|
||||
|
||||
PhotometricInterpretation:
|
||||
@@ -1620,148 +1778,15 @@ export default {
|
||||
DecayCorrection: o.DecayCorrection,
|
||||
EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
})
|
||||
o.myPath = scope.$getObjectName(res.url)
|
||||
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
|
||||
console.log(o.file)
|
||||
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
|
||||
}
|
||||
},
|
||||
{
|
||||
fileName: o.file.name,
|
||||
fileSize: o.file.size,
|
||||
fileType: 'application/dicom',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 1,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
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,
|
||||
{
|
||||
fileName: `${v.seriesUid}.jpg`,
|
||||
fileSize: blob.size,
|
||||
fileType: 'image/jpeg',
|
||||
uploadBatchId: uploadBatchId,
|
||||
batchDataType: 2,
|
||||
trialId: params.trialId,
|
||||
subjectId: params.subjectId,
|
||||
subjectVisitId: params.subjectVisitId,
|
||||
}
|
||||
)
|
||||
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,
|
||||
SOPClassUID: o.SOPClassUID,
|
||||
TransferSytaxUID: o.TransferSytaxUID,
|
||||
MediaStorageSOPInstanceUID:
|
||||
o.MediaStorageSOPInstanceUID,
|
||||
MediaStorageSOPClassUID:
|
||||
o.MediaStorageSOPClassUID,
|
||||
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,
|
||||
|
||||
PhotometricInterpretation:
|
||||
o.PhotometricInterpretation,
|
||||
BitsAllocated: o.BitsAllocated,
|
||||
PixelRepresentation: o.PixelRepresentation,
|
||||
RescaleIntercept: o.RescaleIntercept,
|
||||
RescaleSlope: o.RescaleSlope,
|
||||
ImagePositionPatient: o.ImagePositionPatient,
|
||||
ImageOrientationPatient:
|
||||
o.ImageOrientationPatient,
|
||||
SequenceOfUltrasoundRegions:
|
||||
o.SequenceOfUltrasoundRegions,
|
||||
FrameTime: o.FrameTime,
|
||||
CorrectedImage: o.CorrectedImage,
|
||||
Units: o.Units,
|
||||
DecayCorrection: o.DecayCorrection,
|
||||
EncapsulatedDocument: o.EncapsulatedDocument,
|
||||
})
|
||||
o.myPath = scope.$getObjectName(res.url)
|
||||
Record.Uploaded.push(name)
|
||||
dicomInfo.failedFileCount++
|
||||
Record.FileCount++
|
||||
} else {
|
||||
Record.Failed.push(name)
|
||||
Record.FileCount++
|
||||
}
|
||||
Record.Failed.push(name)
|
||||
Record.FileCount++
|
||||
}
|
||||
// }
|
||||
resolve1()
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
@@ -1779,7 +1804,7 @@ export default {
|
||||
}
|
||||
}
|
||||
params.study.seriesList.push({
|
||||
studyInstanceUid: dicomInfo.studyUid,
|
||||
studyInstanceUid: scope.StudyInstanceUID ? scope.StudyInstanceUID : dicomInfo.studyUid,
|
||||
seriesInstanceUid: v.seriesUid,
|
||||
seriesNumber: v.seriesNumber,
|
||||
seriesTime: v.seriesTime,
|
||||
|
||||
@@ -300,19 +300,7 @@
|
||||
<!-- 审核完成时间 -->
|
||||
<el-table-column prop="AuditTime" :label="$t('trials:crcUpload:table:auditTime')" show-overflow-tooltip
|
||||
width="170" />
|
||||
<el-table-column v-if="
|
||||
hasPermi(
|
||||
[
|
||||
'trials:trials-panel:visit:crc-upload:upload',
|
||||
'trials:trials-panel:visit:crc-upload:submit',
|
||||
'trials:trials-panel:visit:crc-upload:edit',
|
||||
'trials:trials-panel:visit:crc-upload:delete',
|
||||
'trials:trials-panel:visit:crc-upload:back',
|
||||
'trials:trials-panel:visit:crc-upload:authBack'
|
||||
],
|
||||
'||'
|
||||
)
|
||||
" :label="$t('common:action:action')" width="250" fixed="right">
|
||||
<el-table-column :label="$t('common:action:action')" width="250" fixed="right">
|
||||
<template slot-scope="scope">
|
||||
<!-- 上传 -->
|
||||
<el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:upload']" icon="el-icon-upload2" :disabled="!isOCTorIVUS && (scope.row.SubmitState * 1 === 2 ||
|
||||
@@ -320,10 +308,8 @@
|
||||
scope.row.IsLostVisit || (scope.row.IsSubjectQuit && scope.row.SubmitState * 1 !== 2))
|
||||
" circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload(scope.row)" />
|
||||
<!-- 上传2 -->
|
||||
<el-button icon="el-icon-upload2" v-hasPermi="['trials:trials-panel:visit:crc-upload:upload2']" :disabled="!isOCTorIVUS && (scope.row.SubmitState * 1 === 2 ||
|
||||
scope.row.VisitExecuted === 2 ||
|
||||
scope.row.IsLostVisit || (scope.row.IsSubjectQuit && scope.row.SubmitState * 1 !== 2))
|
||||
" circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload2(scope.row)" />
|
||||
<el-button icon="el-icon-upload2"
|
||||
circle :title="$t('trials:crcUpload:action:upload')" @click="CRChandleUpload2(scope.row)" />
|
||||
<!-- 提交 -->
|
||||
<el-button v-hasPermi="['trials:trials-panel:visit:crc-upload:submit']" icon="el-icon-check" :disabled="scope.row.AuditState * 1 > 0 ||
|
||||
scope.row.SubmitState * 1 !== 1 ||
|
||||
|
||||
+1
-1
@@ -52,7 +52,7 @@ module.exports = defineConfig({
|
||||
},
|
||||
|
||||
'/api': {
|
||||
target: 'http://106.14.89.110:30000',
|
||||
target: 'http://192.168.3.99:6100',
|
||||
// target: 'http://101.132.253.119:7010', // uat
|
||||
changeOrigin: true,
|
||||
secure: false,
|
||||
|
||||
Reference in New Issue
Block a user