Compare commits
No commits in common. "e3ad1142073993f0c44b106352b4bbd64cacecd6" and "9a4eb1b210636898774346c749d9aea11484da54" have entirely different histories.
e3ad114207
...
9a4eb1b210
|
|
@ -277,7 +277,7 @@ export default {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss">
|
||||||
.preview-wrapper{
|
.preview-wrapper{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row !important;
|
flex-direction: row !important;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
<template>
|
<template>
|
||||||
<div ref="container" style="width:100%;height:100%" class="dicom-container">
|
<div ref="container" style="width:100%;height:100%" class="dicom-container">
|
||||||
<!-- 访视阅片 -->
|
<!-- 访视阅片 -->
|
||||||
<div v-if="readingCategory=== 1 && (CriterionType === 7)" class="reading-wrapper">
|
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
|
||||||
<VisitReview />
|
|
||||||
</div>
|
|
||||||
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
|
|
||||||
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeave">
|
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeave">
|
||||||
<!-- 阅片 -->
|
<!-- 阅片 -->
|
||||||
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
|
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
|
||||||
|
|
@ -32,7 +29,7 @@
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
|
<div v-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType === 0" class="reading-wrapper">
|
||||||
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeaveCustomize">
|
<el-tabs v-model="activeName" v-loading="loading" :before-leave="beforeLeaveCustomize">
|
||||||
<!-- 阅片 -->
|
<!-- 阅片 -->
|
||||||
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
|
<el-tab-pane :label="$t('trials:reading:tabTitle:review')" name="read">
|
||||||
|
|
@ -174,7 +171,6 @@
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
import { getNextTask, readClinicalData, verifyDefaultQuestionBeAnswer } from '@/api/trials'
|
import { getNextTask, readClinicalData, verifyDefaultQuestionBeAnswer } from '@/api/trials'
|
||||||
import VisitReview from './../dicoms3D/components/VisitReview'
|
|
||||||
import ReadPage from './components/ReadPage'
|
import ReadPage from './components/ReadPage'
|
||||||
import CustomizeReadPage from './customize/CustomizeReadPage'
|
import CustomizeReadPage from './customize/CustomizeReadPage'
|
||||||
import ReportPage from './components/ReportPage'
|
import ReportPage from './components/ReportPage'
|
||||||
|
|
@ -191,7 +187,6 @@ import requestPoolManager from '@/utils/request-pool'
|
||||||
export default {
|
export default {
|
||||||
name: 'Reading',
|
name: 'Reading',
|
||||||
components: {
|
components: {
|
||||||
VisitReview,
|
|
||||||
ReadPage,
|
ReadPage,
|
||||||
ReportPage,
|
ReportPage,
|
||||||
GlobalReview,
|
GlobalReview,
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,273 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-loading="loading" class="study-wrapper">
|
|
||||||
<div class="study-info">
|
|
||||||
<div
|
|
||||||
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
|
|
||||||
:title="taskInfo.SubjectCode"
|
|
||||||
>
|
|
||||||
{{ taskInfo.SubjectCode }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo"
|
|
||||||
:title="visitTaskInfo.TaskBlindName"
|
|
||||||
>
|
|
||||||
{{ visitTaskInfo.TaskBlindName }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="ps">
|
|
||||||
<el-collapse v-model="activeNames">
|
|
||||||
<el-collapse-item v-for="(study, index) in studyList" :key="`${study.StudyId}`" :name="`${study.StudyId}`">
|
|
||||||
<template slot="title">
|
|
||||||
<div
|
|
||||||
v-if="!study.IsCriticalSequence"
|
|
||||||
class="dicom-desc"
|
|
||||||
>
|
|
||||||
<template v-if="taskInfo && taskInfo.IsShowStudyName">
|
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
|
||||||
<span v-if="study.StudyName" :title="study.StudyName" style="margin-left: 5px;">{{ study.StudyName }}</span>
|
|
||||||
<span v-else :title="study.Modalities" style="margin-left: 5px;">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
|
|
||||||
</div>
|
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;" v-if="study.StudyName" >
|
|
||||||
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<template v-else-if="taskInfo && !taskInfo.IsShowStudyName">
|
|
||||||
<div style="text-overflow: ellipsis;overflow: hidden;">
|
|
||||||
<span :title="study.StudyCode">{{ study.StudyCode }}</span>
|
|
||||||
<span :title="study.Modalities">{{ `${study.Modalities} (${study.SeriesCount})` }}</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div v-else>
|
|
||||||
<!-- 关键序列 -->
|
|
||||||
{{ $t('trials:reading:title:keySeries') }}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<div class="dicom-list-container">
|
|
||||||
<div
|
|
||||||
v-for="(series, i) in study.SeriesList"
|
|
||||||
:key="i"
|
|
||||||
style="position:relative;margin-top:1px;"
|
|
||||||
@click="activeSeries(series, i, index)"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
:class="{'series-active': index === activeStudyIndex && i === activeSeriesIndex}"
|
|
||||||
class="series-wrapper"
|
|
||||||
>
|
|
||||||
<div class="series-image">
|
|
||||||
<el-image
|
|
||||||
style="width: 100%;height: 100%;"
|
|
||||||
:src="`${OSSclientConfig.basePath}${series.ImageResizePath}`"
|
|
||||||
fit="fill"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div class="series-text" >
|
|
||||||
<div class="text-desc" v-if="!study.IsCriticalSequence" :title="series.SeriesNumber">
|
|
||||||
#{{ series.SeriesNumber }}
|
|
||||||
</div>
|
|
||||||
<div class="text-desc" v-if="series.Description" :title="series.Description">
|
|
||||||
{{ series.Description }}
|
|
||||||
</div>
|
|
||||||
<div class="text-desc" v-if="series.SliceThickness && !study.IsCriticalSequence">
|
|
||||||
T: {{ parseFloat(series.SliceThickness).toFixed(digitPlaces) }}
|
|
||||||
</div>
|
|
||||||
<div class="text-desc">
|
|
||||||
<span v-show="series.LoadedImageCount < series.InstanceCount">
|
|
||||||
{{ series.Modality }}: {{ series.LoadedImageCount }}/{{ series.InstanceCount }} image
|
|
||||||
</span>
|
|
||||||
<span v-show="series.LoadedImageCount >= series.InstanceCount">{{ series.Modality }}: {{ series.InstanceCount }} image</span>
|
|
||||||
</div>
|
|
||||||
<div v-show="series.IsBeMark">
|
|
||||||
<i class="el-icon-star-on" style="font-size: 16px;color: #ff5722;" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div v-if="series.IsDicom && series.LoadedImageProgress>0 && series.LoadedImageProgress<100" style="width: 100%;">
|
|
||||||
<el-progress
|
|
||||||
:percentage="parseInt((series.LoadedImageProgress).toFixed(2))"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-collapse-item>
|
|
||||||
</el-collapse>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'StudyList',
|
|
||||||
props: {
|
|
||||||
visitTaskInfo: {
|
|
||||||
type: Object,
|
|
||||||
default() {
|
|
||||||
return {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
loading: false,
|
|
||||||
activeNames: [],
|
|
||||||
activeStudyIndex: -1,
|
|
||||||
activeSeriesIndex: -1,
|
|
||||||
taskInfo: null,
|
|
||||||
studyList: [],
|
|
||||||
digitPlaces: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
|
|
||||||
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
|
||||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
|
||||||
this.studyList = this.visitTaskInfo.StudyList
|
|
||||||
if (this.studyList.length === 0) return
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.activeStudy(this.studyList[0].StudyId)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
activeSeries(series, seriesIndex, studyIndex) {
|
|
||||||
this.activeStudyIndex = studyIndex
|
|
||||||
this.activeSeriesIndex = seriesIndex
|
|
||||||
this.$emit('activeSeries', series)
|
|
||||||
},
|
|
||||||
activeStudy(id) {
|
|
||||||
if (this.activeNames.indexOf(id) > -1) return
|
|
||||||
this.activeNames.push(id)
|
|
||||||
},
|
|
||||||
setSeriesActive(studyIndex, seriesIndex) {
|
|
||||||
this.activeStudyIndex = studyIndex
|
|
||||||
this.activeSeriesIndex = seriesIndex
|
|
||||||
let studyId = this.studyList[studyIndex].StudyId
|
|
||||||
if (!studyId) return
|
|
||||||
this.activeStudy(studyId)
|
|
||||||
},
|
|
||||||
getPreviousOrNextSeries(type, series) {
|
|
||||||
let seriseList = this.studyList.map(s => s.SeriesList).flat()
|
|
||||||
let i = seriseList.findIndex(i => i.Id === series.Id && i.StudyId === series.StudyId)
|
|
||||||
if (i === -1) return
|
|
||||||
let newIndex = null
|
|
||||||
if (type === -1) {
|
|
||||||
newIndex = i === 0 ? i : i - 1
|
|
||||||
} else {
|
|
||||||
newIndex = i >= seriseList.length - 1 ? i : i +1
|
|
||||||
}
|
|
||||||
let studyIndex = seriseList[newIndex].StudyIndex
|
|
||||||
let seriesIndex = seriseList[newIndex].SeriesIndex
|
|
||||||
this.setSeriesActive(studyIndex, seriesIndex)
|
|
||||||
this.activeSeries(seriseList[newIndex], seriesIndex, studyIndex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.study-wrapper{
|
|
||||||
width:100%;
|
|
||||||
height: 100%;
|
|
||||||
overflow-y: hidden;
|
|
||||||
overflow-x: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
.study-info {
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: bold;
|
|
||||||
color: #ddd;
|
|
||||||
padding: 5px 0px;
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
background-color: #4c4c4c;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
.dicom-desc{
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 13px;
|
|
||||||
text-align: left;
|
|
||||||
color: #d0d0d0;
|
|
||||||
padding: 2px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
.ps {
|
|
||||||
flex: 1;
|
|
||||||
overflow-anchor: none;
|
|
||||||
touch-action: auto;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
.series-active {
|
|
||||||
background-color: #607d8b!important;
|
|
||||||
border: 1px solid #607d8b!important;
|
|
||||||
}
|
|
||||||
::v-deep.el-progress__text{
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.dicom-list-container{
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
.series-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
padding: 5px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
align-items: center;
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #3a3a3a;
|
|
||||||
.el-progress__text{
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.el-progress-bar{
|
|
||||||
padding-right:0px;
|
|
||||||
}
|
|
||||||
.series-image {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
.series-text {
|
|
||||||
flex: 1;
|
|
||||||
padding-left: 5px;
|
|
||||||
color: #ddd;
|
|
||||||
.text-desc {
|
|
||||||
width: 100px;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 12px;
|
|
||||||
line-height: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::v-deep.el-collapse{
|
|
||||||
border: none;
|
|
||||||
.el-collapse-item{
|
|
||||||
background-color: #000!important;
|
|
||||||
color: #ddd;
|
|
||||||
|
|
||||||
}
|
|
||||||
.el-collapse-item__content{
|
|
||||||
padding-bottom:0px;
|
|
||||||
background-color: #000!important;
|
|
||||||
}
|
|
||||||
.el-collapse-item__header{
|
|
||||||
background-color: #000!important;
|
|
||||||
color: #ddd;
|
|
||||||
border-bottom-color:#5a5a5a;
|
|
||||||
padding-left: 5px;
|
|
||||||
// height: 50px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
::v-deep .el-progress-bar__inner{
|
|
||||||
transition: width 0s ease;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,551 +0,0 @@
|
||||||
<template>
|
|
||||||
<div
|
|
||||||
ref="viewport"
|
|
||||||
class="viewport-wrapper"
|
|
||||||
@mouseup="sliderMouseup"
|
|
||||||
@mousemove="sliderMousemove"
|
|
||||||
@mouseleave="sliderMouseleave"
|
|
||||||
>
|
|
||||||
<div class="left-top-text" v-if="series && taskInfo">
|
|
||||||
<div
|
|
||||||
v-if="taskInfo.IsExistsClinicalData"
|
|
||||||
class="cd-info"
|
|
||||||
:title="$t('trials:reading:button:clinicalData')"
|
|
||||||
>
|
|
||||||
<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>
|
|
||||||
<div>Series: #{{ series.SeriesNumber }}</div>
|
|
||||||
<div>Image: #{{ `${series.SliceIndex + 1}/${series.ImageIds.length}` }}</div>
|
|
||||||
<div>{{series.Modality}}</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
v-if="series && taskInfo && taskInfo.IsReadingTaskViewInOrder === 1"
|
|
||||||
class="top-center-tool"
|
|
||||||
>
|
|
||||||
<div class="toggle-visit-container">
|
|
||||||
<div
|
|
||||||
class="arrw_icon"
|
|
||||||
:style="{ cursor: series.TaskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum !== 0 ? '#fff': '#6b6b6b' }"
|
|
||||||
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, -1)"
|
|
||||||
@dblclick.stop="preventDefault($event)"
|
|
||||||
>
|
|
||||||
<i class="el-icon-caret-left" />
|
|
||||||
</div>
|
|
||||||
<div class="arrow_text">
|
|
||||||
{{ series.TaskInfo.TaskBlindName }}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
class="arrw_icon"
|
|
||||||
:style="{ cursor: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: series.TaskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff': '#6b6b6b' }"
|
|
||||||
@click.stop.prevent="toggleTask($event, series.TaskInfo.VisitTaskNum, 1)"
|
|
||||||
@dblclick.stop="preventDefault($event)"
|
|
||||||
>
|
|
||||||
<i class="el-icon-caret-right" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-top-text" v-if="series">
|
|
||||||
<div>{{ series.Description }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="left-bottom-text" v-if="series">
|
|
||||||
<div v-show="mousePosition.index.length > 0">
|
|
||||||
Pos: {{ mousePosition.index[0] }}, {{ mousePosition.index[1] }}, {{ mousePosition.index[2] }}
|
|
||||||
</div>
|
|
||||||
<div v-if="(series.Modality === 'CT' || series.Modality === 'DR' || series.Modality === 'CR') && mousePosition.value">
|
|
||||||
HU: {{ mousePosition.value }}
|
|
||||||
</div>
|
|
||||||
<div v-else-if="(series.Modality === 'PT' && mousePosition.value)">
|
|
||||||
SUVbw(g/ml): {{ digitPlaces === -1 ?mousePosition.value.toFixed(3) :mousePosition.value.toFixed(digitPlaces) }}
|
|
||||||
</div>
|
|
||||||
<div v-else-if="mousePosition.value">
|
|
||||||
Density: {{ mousePosition.value }}
|
|
||||||
</div>
|
|
||||||
<div v-show="imageInfo.size">
|
|
||||||
W*H: {{ imageInfo.size }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right-bottom-text" v-if="series">
|
|
||||||
<div v-show="imageInfo.location">Location: {{ `${Number(imageInfo.location).toFixed(digitPlaces)} mm` }}</div>
|
|
||||||
<div v-show="series.SliceThickness">Slice Thickness: {{ `${Number(series.SliceThickness).toFixed(digitPlaces)} mm` }}</div>
|
|
||||||
<div v-show="imageInfo.wwwc ">WW/WL: {{ imageInfo.wwwc }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="orientation-top">
|
|
||||||
{{ markers.top }}
|
|
||||||
</div>
|
|
||||||
<div class="orientation-right">
|
|
||||||
{{ markers.right }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="orientation-bottom">
|
|
||||||
{{ markers.bottom }}
|
|
||||||
</div>
|
|
||||||
<div class="orientation-left">
|
|
||||||
{{ markers.left }}
|
|
||||||
</div>
|
|
||||||
<div ref="sliderBox" class="right-slider-box" @click.stop="clickSlider($event)">
|
|
||||||
<div :style="{top: sliderInfo.height + '%'}" class="slider" @click.stop.prevent="() => {return}" @mousedown.stop="sliderMousedown($event)" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import * as cornerstonejs from '@cornerstonejs/core'
|
|
||||||
import {
|
|
||||||
RenderingEngine,
|
|
||||||
Enums,
|
|
||||||
imageLoader,
|
|
||||||
metaData,
|
|
||||||
getRenderingEngine,
|
|
||||||
eventTarget,
|
|
||||||
utilities as csUtils
|
|
||||||
} from '@cornerstonejs/core'
|
|
||||||
import * as cornerstoneTools from '@cornerstonejs/tools'
|
|
||||||
import { vec3, mat4 } from 'gl-matrix'
|
|
||||||
export default {
|
|
||||||
name: 'Viewport',
|
|
||||||
props: {
|
|
||||||
renderingEngineId: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
viewportId: {
|
|
||||||
type: String,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
viewportIndex: {
|
|
||||||
type: Number,
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
data(){
|
|
||||||
return {
|
|
||||||
element: '',
|
|
||||||
series: null,
|
|
||||||
taskInfo: null,
|
|
||||||
sliderInfo: {
|
|
||||||
oldB: null,
|
|
||||||
oldM: null,
|
|
||||||
isMove: false,
|
|
||||||
height: 0
|
|
||||||
},
|
|
||||||
mousePosition: {
|
|
||||||
index: [],
|
|
||||||
value: null,
|
|
||||||
modalityUnit: '',
|
|
||||||
world: []
|
|
||||||
},
|
|
||||||
imageInfo: {
|
|
||||||
zoom: null,
|
|
||||||
size: null,
|
|
||||||
location: null,
|
|
||||||
sliceThickness: null,
|
|
||||||
wwwc: null
|
|
||||||
},
|
|
||||||
digitPlaces: 2,
|
|
||||||
orientationMarkers: [],
|
|
||||||
originalMarkers: [],
|
|
||||||
markers: { top: '', right: '', bottom: '', left: '' },
|
|
||||||
playClipState: false,
|
|
||||||
wwwcIdx: 2
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
|
|
||||||
let digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
|
||||||
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
|
||||||
this.$nextTick(()=>{
|
|
||||||
this.initViewport()
|
|
||||||
})
|
|
||||||
console.log(cornerstonejs)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
initViewport() {
|
|
||||||
this.element = this.$refs['viewport']
|
|
||||||
const resizeObserver = new ResizeObserver(() => {
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
if (renderingEngine) {
|
|
||||||
renderingEngine.resize(true, false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
this.element.oncontextmenu = (e) => e.preventDefault()
|
|
||||||
resizeObserver.observe(this.element)
|
|
||||||
this.element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
|
||||||
this.element.addEventListener('CORNERSTONE_VOI_MODIFIED', this.voiModified)
|
|
||||||
|
|
||||||
this.element.addEventListener('CORNERSTONE_TOOLS_MOUSE_MOVE', this.cornerstoneToolsMouseMove)
|
|
||||||
this.element.addEventListener('mouseleave', () => {
|
|
||||||
this.mousePosition.index = []
|
|
||||||
})
|
|
||||||
// console.log(cornerstonejs,cornerstoneTools)
|
|
||||||
// element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
|
||||||
},
|
|
||||||
stackNewImage(e) {
|
|
||||||
const { detail } = e
|
|
||||||
this.series.SliceIndex = detail.imageIdIndex
|
|
||||||
this.sliderInfo.height = detail.imageIdIndex * 100 / (this.series.ImageIds.length - 1)
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
let zoom = viewport.getZoom()
|
|
||||||
this.imageInfo.zoom = zoom.toFixed(4)
|
|
||||||
this.imageInfo.size = `${detail.image.columns}*${detail.image.rows}`
|
|
||||||
const imagePlaneModule = metaData.get('imagePlaneModule', detail.imageId)
|
|
||||||
this.imageInfo.location = imagePlaneModule.sliceLocation
|
|
||||||
// this.imageInfo.wwwc = `${Math.round(detail.image.windowWidth)}/${Math.round(detail.image.windowCenter)}`
|
|
||||||
this.getOrientationMarker()
|
|
||||||
},
|
|
||||||
voiModified(e) {
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
const properties = viewport.getProperties()
|
|
||||||
if (properties && properties.voiRange) {
|
|
||||||
var { lower, upper } = properties.voiRange
|
|
||||||
const { windowWidth, windowCenter } = csUtils.windowLevel.toWindowLevel(
|
|
||||||
lower,
|
|
||||||
upper
|
|
||||||
)
|
|
||||||
this.imageInfo.wwwc = `${Math.round(windowWidth)}/${Math.round(windowCenter)}`
|
|
||||||
}
|
|
||||||
},
|
|
||||||
getOrientationMarker() {
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
const { viewUp, viewPlaneNormal } = viewport.getCamera()
|
|
||||||
|
|
||||||
const viewRight = vec3.create()
|
|
||||||
vec3.cross(viewRight, viewUp, viewPlaneNormal)
|
|
||||||
|
|
||||||
const columnCosines = [-viewUp[0], -viewUp[1], -viewUp[2]]
|
|
||||||
const rowCosines = viewRight
|
|
||||||
const rowString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(rowCosines)
|
|
||||||
const columnString = cornerstoneTools.utilities.orientation.getOrientationStringLPS(columnCosines)
|
|
||||||
const oppositeRowString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(rowString)
|
|
||||||
const oppositeColumnString = cornerstoneTools.utilities.orientation.invertOrientationStringLPS(columnString)
|
|
||||||
this.markers.top = oppositeColumnString
|
|
||||||
this.markers.right = rowString
|
|
||||||
this.markers.bottom = columnString
|
|
||||||
this.markers.left = oppositeRowString
|
|
||||||
this.orientationMarkers = [oppositeColumnString, rowString, columnString, oppositeRowString]
|
|
||||||
if (this.originalMarkers.length === 0) {
|
|
||||||
this.originalMarkers = [...this.orientationMarkers]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setMarkers() {
|
|
||||||
let markers = [...this.orientationMarkers]
|
|
||||||
for (const key in this.markers) {
|
|
||||||
let v = markers.shift(0)
|
|
||||||
this.markers[key] = v
|
|
||||||
}
|
|
||||||
},
|
|
||||||
resetOrientationMarkers() {
|
|
||||||
if (this.originalMarkers.length > 0) {
|
|
||||||
console.log(this.originalMarkers)
|
|
||||||
this.orientationMarkers = [...this.originalMarkers]
|
|
||||||
this.setMarkers()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
rotateOrientationMarkers(type) {
|
|
||||||
if (this.orientationMarkers.length > 0) {
|
|
||||||
if (type === 1) {
|
|
||||||
this.resetOrientationMarkers()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
let markers = [...this.orientationMarkers]
|
|
||||||
if (type === 2) {
|
|
||||||
// 垂直翻转
|
|
||||||
this.orientationMarkers[0] = markers[2]
|
|
||||||
this.orientationMarkers[2] = markers[0]
|
|
||||||
} else if (type === 3) {
|
|
||||||
// 水平翻转
|
|
||||||
this.orientationMarkers[1] = markers[3]
|
|
||||||
this.orientationMarkers[3] = markers[1]
|
|
||||||
} else if (type === 4) {
|
|
||||||
// 左转90度
|
|
||||||
this.orientationMarkers = markers.slice(1, 4).concat(markers[0])
|
|
||||||
} else if (type === 5) {
|
|
||||||
// 右转90度
|
|
||||||
this.orientationMarkers = [markers[3]].concat(markers.slice(0, 3))
|
|
||||||
}
|
|
||||||
this.setMarkers()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggleClipPlay(isPlay, framesPerSecond) {
|
|
||||||
this.playClipState = isPlay
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
|
|
||||||
if (isPlay) {
|
|
||||||
cornerstoneTools.utilities.cine.playClip(viewport.element, { framesPerSecond })
|
|
||||||
} else {
|
|
||||||
cornerstoneTools.utilities.cine.stopClip(viewport.element)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scrollPage(type) {
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
const currentImageIdIndex = viewport.getCurrentImageIdIndex();
|
|
||||||
const numImages = viewport.getImageIds().length;
|
|
||||||
let newImageIdIndex = null;
|
|
||||||
if (type === 0) {
|
|
||||||
newImageIdIndex = 0
|
|
||||||
} else if (type === -1) {
|
|
||||||
newImageIdIndex = currentImageIdIndex === 0 ? currentImageIdIndex : currentImageIdIndex - 1
|
|
||||||
} else if (type === 1) {
|
|
||||||
newImageIdIndex = currentImageIdIndex === numImages - 1 ? currentImageIdIndex : currentImageIdIndex + 1
|
|
||||||
} else if (type === 99999) {
|
|
||||||
newImageIdIndex = numImages -1
|
|
||||||
}
|
|
||||||
viewport.setImageIdIndex(newImageIdIndex);
|
|
||||||
},
|
|
||||||
setZoom(ratio) {
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId);
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId);
|
|
||||||
|
|
||||||
const zoom = viewport.getZoom();
|
|
||||||
if (ratio > 0) {
|
|
||||||
viewport.setZoom(zoom * 1.05);
|
|
||||||
} else {
|
|
||||||
viewport.setZoom(zoom / 1.05);
|
|
||||||
}
|
|
||||||
viewport.render();
|
|
||||||
},
|
|
||||||
resize(forceFitToWindow) {
|
|
||||||
console.log('resize: ', forceFitToWindow)
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId);
|
|
||||||
renderingEngine.resize(true, forceFitToWindow)
|
|
||||||
},
|
|
||||||
async setSeriesInfo(obj){
|
|
||||||
if (this.series && obj.Id === this.series.Id && obj.Description === this.series.Description) return
|
|
||||||
this.series = {...obj}
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
await viewport.setStack(obj.ImageIds, obj.SliceIndex)
|
|
||||||
cornerstoneTools.utilities.stackPrefetch.enable(viewport.element);
|
|
||||||
viewport.render()
|
|
||||||
},
|
|
||||||
cornerstoneToolsMouseMove(e) {
|
|
||||||
const { currentPoints } = e.detail
|
|
||||||
const worldPoint = currentPoints.world
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(this.viewportId)
|
|
||||||
const imageData = viewport.getImageData()
|
|
||||||
if (!imageData) return
|
|
||||||
const index = imageData.imageData.worldToIndex(worldPoint)
|
|
||||||
index[0] = Math.floor(index[0])
|
|
||||||
index[1] = Math.floor(index[1])
|
|
||||||
index[2] = Math.floor(index[2])
|
|
||||||
this.mousePosition.index = index
|
|
||||||
},
|
|
||||||
toggleTask(evt, visitTaskNum, i) {
|
|
||||||
this.$emit('activeViewport', this.viewportIndex)
|
|
||||||
const num = visitTaskNum + i
|
|
||||||
if (num >= 0 && num <= this.taskInfo.VisitNum) {
|
|
||||||
this.$emit('toggleTaskByViewport', {series: this.series, visitTaskNum: num})
|
|
||||||
}
|
|
||||||
|
|
||||||
evt.stopImmediatePropagation()
|
|
||||||
evt.stopPropagation()
|
|
||||||
evt.preventDefault()
|
|
||||||
},
|
|
||||||
viewCD(taskId) {
|
|
||||||
this.$emit('previewCD', taskId)
|
|
||||||
},
|
|
||||||
setWwwcIdx(idx) {
|
|
||||||
this.wwwcIdx = idx
|
|
||||||
},
|
|
||||||
clickSlider(e) {
|
|
||||||
const height = e.offsetY * 100 / this.$refs['sliderBox'].clientHeight
|
|
||||||
this.sliderInfo.height = height
|
|
||||||
let sliceIdx = Math.trunc(this.series.ImageIds.length * height / 100)
|
|
||||||
sliceIdx = sliceIdx >= this.series.ImageIds.length ? this.series.ImageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(
|
|
||||||
this.viewportId
|
|
||||||
)
|
|
||||||
viewport.setImageIdIndex(sliceIdx)
|
|
||||||
viewport.render()
|
|
||||||
},
|
|
||||||
sliderMouseup(e) {
|
|
||||||
this.sliderInfo.isMove = false
|
|
||||||
},
|
|
||||||
sliderMousedown(e) {
|
|
||||||
const boxHeight = this.$refs['sliderBox'].clientHeight
|
|
||||||
this.sliderInfo.oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
|
|
||||||
this.sliderInfo.oldM = e.clientY
|
|
||||||
this.sliderInfo.isMove = true
|
|
||||||
e.stopImmediatePropagation()
|
|
||||||
e.stopPropagation()
|
|
||||||
e.preventDefault()
|
|
||||||
},
|
|
||||||
sliderMousemove(e) {
|
|
||||||
if (!this.sliderInfo.isMove) return
|
|
||||||
const delta = this.sliderInfo.oldB - (this.sliderInfo.oldM - e.clientY)
|
|
||||||
const boxHeight = this.$refs['sliderBox'].clientHeight
|
|
||||||
if (delta < 0) return
|
|
||||||
if (delta > boxHeight) return
|
|
||||||
const height = delta * 100 / boxHeight
|
|
||||||
let sliceIdx = Math.trunc(this.series.ImageIds.length * height / 100)
|
|
||||||
sliceIdx = sliceIdx >= this.series.ImageIds.length ? this.series.ImageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
||||||
this.sliderInfo.height = height
|
|
||||||
const renderingEngine = getRenderingEngine(this.renderingEngineId)
|
|
||||||
const viewport = renderingEngine.getViewport(
|
|
||||||
this.viewportId
|
|
||||||
)
|
|
||||||
viewport.setImageIdIndex(sliceIdx)
|
|
||||||
viewport.render()
|
|
||||||
},
|
|
||||||
sliderMouseleave(e) {
|
|
||||||
if (!this.sliderInfo.isMove) return
|
|
||||||
this.sliderInfo.isMove = false
|
|
||||||
},
|
|
||||||
preventDefault(e) {
|
|
||||||
e.stopImmediatePropagation()
|
|
||||||
e.stopPropagation()
|
|
||||||
e.preventDefault()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.viewport-wrapper {
|
|
||||||
width:100%;
|
|
||||||
height:100%;
|
|
||||||
position: relative;
|
|
||||||
.left-top-text {
|
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
|
||||||
top: 5px;
|
|
||||||
color: #ddd;
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 12px;
|
|
||||||
.cd-info {
|
|
||||||
color: #ddd;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
.subject-info {
|
|
||||||
color:#f44336;
|
|
||||||
padding: 5px 0px;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.top-center-tool {
|
|
||||||
position: absolute;
|
|
||||||
left:50%;
|
|
||||||
top: 5px;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
.toggle-visit-container {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
.arrw_icon{
|
|
||||||
width: 20px;
|
|
||||||
height: 20px;
|
|
||||||
background-color: #3f3f3f;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 20px;
|
|
||||||
border-radius: 10%;
|
|
||||||
}
|
|
||||||
.arrow_text{
|
|
||||||
height: 20px;
|
|
||||||
line-height: 20px;
|
|
||||||
background-color: #00000057;
|
|
||||||
color: #fff;
|
|
||||||
padding:0 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.right-top-text {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
top: 5px;
|
|
||||||
color: #ddd;
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.left-bottom-text {
|
|
||||||
position: absolute;
|
|
||||||
left: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
color: #ddd;
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.right-bottom-text {
|
|
||||||
position: absolute;
|
|
||||||
right: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
color: #ddd;
|
|
||||||
z-index: 1;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
.right-slider-box {
|
|
||||||
position: absolute;
|
|
||||||
right: 1px;
|
|
||||||
height: calc(100% - 140px);
|
|
||||||
transform: translateY(-50%);
|
|
||||||
top: calc(50% - 30px);
|
|
||||||
width: 10px;
|
|
||||||
background: #333;
|
|
||||||
z-index: 1;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.right-slider-box:after{
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
bottom: -20px;
|
|
||||||
left: 0;
|
|
||||||
height: 20px;
|
|
||||||
width: 100%;
|
|
||||||
background: #333;
|
|
||||||
}
|
|
||||||
.slider {
|
|
||||||
height: 20px;
|
|
||||||
width: 100%;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
z-index:10;
|
|
||||||
background: #9e9e9e;
|
|
||||||
cursor: move
|
|
||||||
}
|
|
||||||
.orientation-top {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
top: 30px;
|
|
||||||
color: #f44336;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.orientation-bottom {
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
bottom: 15px;
|
|
||||||
color: #f44336;
|
|
||||||
transform: translateX(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.orientation-left {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
left: 15px;
|
|
||||||
color: #f44336;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
.orientation-right {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 15px;
|
|
||||||
color: #f44336;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,79 +0,0 @@
|
||||||
<template>
|
|
||||||
<div class="visit-review-container">
|
|
||||||
<el-tabs
|
|
||||||
v-model="activeName"
|
|
||||||
>
|
|
||||||
<!-- 阅片 -->
|
|
||||||
<el-tab-pane
|
|
||||||
v-if="taskInfo"
|
|
||||||
:label="$t('trials:reading:tabTitle:review')"
|
|
||||||
name="read"
|
|
||||||
>
|
|
||||||
<read-page />
|
|
||||||
</el-tab-pane>
|
|
||||||
<!-- 报告 -->
|
|
||||||
<el-tab-pane
|
|
||||||
v-if="taskInfo && !taskInfo.IseCRFShowInDicomReading"
|
|
||||||
:label="$t('trials:reading:tabTitle:report')"
|
|
||||||
name="report"
|
|
||||||
>
|
|
||||||
<report-page v-if="activeName === 'report'" />
|
|
||||||
</el-tab-pane>
|
|
||||||
</el-tabs>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import ReadPage from './ReadPage'
|
|
||||||
import ReportPage from './ReportPage'
|
|
||||||
export default {
|
|
||||||
name: 'VisitReview',
|
|
||||||
components: {
|
|
||||||
ReadPage,
|
|
||||||
ReportPage
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
activeName: 'read',
|
|
||||||
taskInfo: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.visit-review-container {
|
|
||||||
height: 100vh;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
background-color: #000;
|
|
||||||
padding: 5px;
|
|
||||||
::v-deep .el-tabs {
|
|
||||||
height: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
.el-tabs__item {
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
.el-tabs__item.is-active {
|
|
||||||
color: #428bca;
|
|
||||||
}
|
|
||||||
.el-tabs__item:hover {
|
|
||||||
color: #428bca;
|
|
||||||
}
|
|
||||||
.el-tabs__header {
|
|
||||||
height: 50px;
|
|
||||||
margin:0px;
|
|
||||||
}
|
|
||||||
.el-tabs__content {
|
|
||||||
flex: 1;
|
|
||||||
margin:0px;
|
|
||||||
}
|
|
||||||
.el-tab-pane {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -1,193 +0,0 @@
|
||||||
const config = {
|
|
||||||
"standards": [
|
|
||||||
{
|
|
||||||
"type": 1,
|
|
||||||
"name": "RECIST 1.1",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "直径测量工具",
|
|
||||||
"icon": "length",
|
|
||||||
"toolName": "Length",
|
|
||||||
"i18nKey": "trials:reading:button:length"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "长短径测量工具",
|
|
||||||
"icon": "bidirection",
|
|
||||||
"toolName": "Bidirectional",
|
|
||||||
"i18nKey": "trials:reading:button:bidirectional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 2,
|
|
||||||
"name": "Lugano 2014",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "直径测量工具",
|
|
||||||
"icon": "length",
|
|
||||||
"toolName": "Length",
|
|
||||||
"i18nKey": "trials:reading:button:length"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "长短径测量工具",
|
|
||||||
"icon": "bidirection",
|
|
||||||
"toolName": "Bidirectional",
|
|
||||||
"i18nKey": "trials:reading:button:bidirectional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 3,
|
|
||||||
"name": "iRECIST",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "直径测量工具",
|
|
||||||
"icon": "length",
|
|
||||||
"toolName": "Length",
|
|
||||||
"i18nKey": "trials:reading:button:length"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "长短径测量工具",
|
|
||||||
"icon": "bidirection",
|
|
||||||
"toolName": "Bidirectional",
|
|
||||||
"i18nKey": "trials:reading:button:bidirectional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 7,
|
|
||||||
"name": "mRECIST HCC",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "直径测量工具",
|
|
||||||
"icon": "length",
|
|
||||||
"toolName": "Length",
|
|
||||||
"i18nKey": "trials:reading:button:length"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "长短径测量工具",
|
|
||||||
"icon": "bidirection",
|
|
||||||
"toolName": "Bidirectional",
|
|
||||||
"i18nKey": "trials:reading:button:bidirectional"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 10,
|
|
||||||
"name": "PCWG3",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 17,
|
|
||||||
"name": "PCWG3",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "直径测量工具",
|
|
||||||
"icon": "length",
|
|
||||||
"toolName": "Length",
|
|
||||||
"i18nKey": "trials:reading:button:length"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "矩形工具",
|
|
||||||
"icon": "rectangle",
|
|
||||||
"toolName": "RectangleRoi",
|
|
||||||
"i18nKey": "trials:reading:button:rectangle"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "箭头工具",
|
|
||||||
"icon": "arrow",
|
|
||||||
"toolName": "ArrowAnnotate",
|
|
||||||
"i18nKey": "trials:reading:button:arrowAnnotate"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 19,
|
|
||||||
"name": "IVUS定量评估",
|
|
||||||
"tools": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 20,
|
|
||||||
"name": "OCT定量评估",
|
|
||||||
"tools": []
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": 21,
|
|
||||||
"name": "MRI-PDFF",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"name": "圆形测量",
|
|
||||||
"icon": "oval",
|
|
||||||
"toolName": "Probe",
|
|
||||||
"i18nKey": "trials:reading:button:circle"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
const getTools = (criterionType) => {
|
|
||||||
const standard = config.standards.find(s => s.type === criterionType);
|
|
||||||
return standard?.tools || [];
|
|
||||||
};
|
|
||||||
export {config, getTools}
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
<template>
|
|
||||||
<div v-loading="loading" class="reading-viewer-container">
|
|
||||||
<!-- 访视阅片 -->
|
|
||||||
<visit-review
|
|
||||||
v-if="taskInfo && taskInfo.ReadingCategory=== 1"
|
|
||||||
/>
|
|
||||||
<!-- 临床数据 -->
|
|
||||||
<el-dialog
|
|
||||||
:visible.sync="clinicalDataVisible"
|
|
||||||
:custom-class="isClinicalDataFullscreen?'full-dialog-container':'dialog-container'"
|
|
||||||
:show-close="false"
|
|
||||||
:close-on-click-modal="false"
|
|
||||||
:fullscreen="isClinicalDataFullscreen"
|
|
||||||
>
|
|
||||||
<span slot="title" class="dialog-footer">
|
|
||||||
<!-- 当前阅片任务存在临床数据,请查看。若已查看,请点击“确认” -->
|
|
||||||
<span v-if="!closeCDVisible">{{ $t('trials:reading:dagTitle:msg1') }}</span>
|
|
||||||
<div style="position: absolute;right: 20px;top: 10px;">
|
|
||||||
<svg-icon :icon-class="isClinicalDataFullscreen?'exit-fullscreen':'fullscreen'" style="cursor: pointer;font-size: 20px;" @click="isClinicalDataFullscreen=!isClinicalDataFullscreen" />
|
|
||||||
<svg-icon v-if="closeCDVisible" icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;" @click="clinicalDataVisible = false" />
|
|
||||||
</div>
|
|
||||||
</span>
|
|
||||||
<div style="height: 100%;margin:0;display: flex;flex-direction: column;">
|
|
||||||
<clinical-data
|
|
||||||
v-if="clinicalDataVisible"
|
|
||||||
style="flex: 1"
|
|
||||||
:trial-id="trialId"
|
|
||||||
:subject-id="taskInfo.SubjectId"
|
|
||||||
:visit-task-id="cdVisitTaskId"
|
|
||||||
:is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
|
|
||||||
/>
|
|
||||||
<div v-if="!closeCDVisible" style="text-align:right">
|
|
||||||
<el-button type="primary" @click="handleConfirmCD">{{ $t('trials:reading:button:confirm') }}</el-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</el-dialog>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import VisitReview from './components/VisitReview'
|
|
||||||
import ClinicalData from '@/views/trials/trials-panel/reading/clinical-data'
|
|
||||||
export default {
|
|
||||||
name:'Dicoms3d',
|
|
||||||
components: { VisitReview,ClinicalData },
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
taskInfo: null,
|
|
||||||
trialId: '',
|
|
||||||
loading: false,
|
|
||||||
clinicalDataVisible: false,
|
|
||||||
isClinicalDataFullscreen: false,
|
|
||||||
closeCDVisible: false,
|
|
||||||
cdVisitTaskId: ''
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.trialId = this.$route.query.trialId
|
|
||||||
this.getTaskInfo()
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
async getTaskInfo() {
|
|
||||||
this.loading = true
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
subjectId: this.$route.query.subjectId,
|
|
||||||
trialId: this.$route.query.trialId,
|
|
||||||
subjectCode: this.$route.query.subjectCode,
|
|
||||||
visitTaskId: this.$route.query.visitTaskId,
|
|
||||||
trialReadingCriterionId: this.$route.query.TrialReadingCriterionId
|
|
||||||
}
|
|
||||||
const res = await getNextTask(params)
|
|
||||||
this.taskInfo = res.Result
|
|
||||||
localStorage.setItem('taskInfo', JSON.stringify(res.Result))
|
|
||||||
localStorage.setItem('digitPlaces', JSON.stringify(res.Result.DigitPlaces))
|
|
||||||
this.loading = false
|
|
||||||
this.$nextTick(() => {
|
|
||||||
if (this.taskInfo.IsExistsClinicalData && this.taskInfo.IsNeedReadClinicalData && !this.taskInfo.IsReadClinicalData) {
|
|
||||||
this.isClinicalDataFullscreen = false
|
|
||||||
this.clinicalDataVisible = true
|
|
||||||
this.cdVisitTaskId = this.taskInfo.VisitTaskId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
this.loading = false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.reading-viewer-container {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
// ::v-deep .dialog-container{
|
|
||||||
// margin-top: 50px !important;
|
|
||||||
// width:75%;
|
|
||||||
// height:80%;
|
|
||||||
// }
|
|
||||||
// ::v-deep .el-dialog__body{
|
|
||||||
// padding: 10px;
|
|
||||||
// height: calc(100% - 70px);
|
|
||||||
// }
|
|
||||||
// .el-dialog__header{
|
|
||||||
// position: relative;
|
|
||||||
// }
|
|
||||||
// .full-dialog-container{
|
|
||||||
// ::v-deep .is-fullscreen .el-dialog__body{
|
|
||||||
// height: calc(100% - 70px);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
@ -295,8 +295,8 @@ export default {
|
||||||
async toggleTaskByViewer(visitTaskNum) {
|
async toggleTaskByViewer(visitTaskNum) {
|
||||||
const i = this.visitTaskList.findIndex(v => v.VisitTaskNum === visitTaskNum)
|
const i = this.visitTaskList.findIndex(v => v.VisitTaskNum === visitTaskNum)
|
||||||
if (i === -1) return
|
if (i === -1) return
|
||||||
const visitTaskId = this.visitTaskList[i].VisitTaskId
|
const visistTaskId = this.visitTaskList[i].VisitTaskId
|
||||||
this.setActiveTaskVisitId(visitTaskId, true)
|
this.setActiveTaskVisitId(visistTaskId, true)
|
||||||
},
|
},
|
||||||
// 设置激活的访视
|
// 设置激活的访视
|
||||||
async setActiveTaskVisitId(id, isInitActiveFile = false) {
|
async setActiveTaskVisitId(id, isInitActiveFile = false) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue