阅片页竖屏适配、mrecist新病灶状态
continuous-integration/drone/push Build is passing Details

main
wangxiaoshuang 2025-09-01 14:18:22 +08:00
parent e582da7500
commit 1ec8c81d0e
3 changed files with 286 additions and 154 deletions

View File

@ -367,7 +367,7 @@
</div>
</div>
<div class="dicom-viewers">
<div ref="container" class="viewer-container" :class="['box', `box_${layoutRow}_${layoutCol}`]">
<div ref="container" class="viewer-container" :class="['box', `box_${AspectRatio < 1 ? layoutCol : layoutRow}_${AspectRatio < 1 ? layoutRow : layoutCol}`]">
<div
v-for="i in maxCanvas"
:key="i"
@ -396,79 +396,84 @@
/>
</div>
</div>
<div ref="form-container" class="form-container">
<div class="form-wrapper">
<RecistBMQuestionList
v-if="CriterionType === 17"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<IRecistQuestionList
v-else-if="CriterionType === 3"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<PCWGQuestionList
v-else-if="CriterionType === 10"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<LuganoQuestionList
v-else-if="CriterionType === 2"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<RecistQuestionList
v-else-if="CriterionType === 1"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<MRecistQuestionList
v-else-if="CriterionType === 7"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<h2 v-else style="color:#ddd">
Developing...
</h2>
<div ref="form-container" :class="{ 'form-container': true, listHide: !listShow }">
<div class="list_btn" @click.stop="clickShow"
:title="listShow ? $t('reading:dicom:dicom-list:hiden') : $t('reading:dicom:dicom-list:show')">
<i :class="listShow ? 'el-icon-right' : 'el-icon-back'"></i>
</div>
<div v-if="iseCRFShowInDicomReading && currentReadingTaskState < 2" class="form-footer">
<el-button
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button
type="primary"
size="small"
@click="submit"
>
<!-- 提交 -->
{{ $t('common:button:submit') }}
</el-button>
</div>
<transition name="ListBox">
<div class="form-wrapper" v-show="listShow">
<RecistBMQuestionList
v-if="CriterionType === 17"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<IRecistQuestionList
v-else-if="CriterionType === 3"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<PCWGQuestionList
v-else-if="CriterionType === 10"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<LuganoQuestionList
v-else-if="CriterionType === 2"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<RecistQuestionList
v-else-if="CriterionType === 1"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<MRecistQuestionList
v-else-if="CriterionType === 7"
ref="measurementList"
:question-form-change-state="questionFormChangeState"
:question-form-change-num="questionFormChangeNum"
:is-show="isShow"
:is-reading-show-subject-info="isReadingShowSubjectInfo"
/>
<h2 v-else style="color:#ddd">
Developing...
</h2>
</div>
<div v-if="iseCRFShowInDicomReading && currentReadingTaskState < 2" v-show="listShow" class="form-footer">
<el-button
type="primary"
size="small"
@click="skipTask"
>
<!-- 跳过 -->
{{ $t('trials:readingReport:button:skip') }}
</el-button>
<el-button
type="primary"
size="small"
@click="submit"
>
<!-- 提交 -->
{{ $t('common:button:submit') }}
</el-button>
</div>
</transition>
</div>
</div>
@ -792,6 +797,12 @@ export default {
default() {
return 0
}
},
studyShow: {
type: Boolean,
default() {
return true
}
}
},
data() {
@ -901,6 +912,9 @@ export default {
ctSeries: [],
petSeries: [],
petctWindow: null,
AspectRatio: 1,
listShow: true
}
},
@ -1104,6 +1118,14 @@ export default {
this.petctWindow.close()
}
})
let windowWidth = document.documentElement.clientWidth;
let windowHeight = document.documentElement.clientHeight;
this.AspectRatio = windowWidth / windowHeight
window.onresize = () => {
let windowWidth = document.documentElement.clientWidth;
let windowHeight = document.documentElement.clientHeight;
this.AspectRatio = windowWidth / windowHeight
};
},
beforeDestroy() {
DicomEvent.$off('updateImage')
@ -1125,8 +1147,13 @@ export default {
this.petctWindow.close()
}
})
window.onresize = null
},
methods: {
clickShow() {
this.listShow = !this.listShow;
this.changeLayout()
},
async getWwcTpl() {
// const loading = this.$loading({ fullscreen: true })
try {
@ -1804,11 +1831,15 @@ export default {
//
setCanvasStyle() {
this.canvasW = (window.innerWidth - 570) / this.layoutCol + 'px'
this.canvasH = (window.innerHeight - 130) / this.layoutRow + 'px'
let w = 570
if (!this.studyShow) w -= 170
if (!this.listShow) w -= 330
this.canvasW = (window.innerWidth - w) / (this.AspectRatio < 1 ? this.layoutRow : this.layoutCol) + 'px'
this.canvasH = (window.innerHeight - 130) / (this.AspectRatio < 1 ? this.layoutCol : this.layoutRow) + 'px'
},
//
changeLayout(name) {
if (!name) name = this.layout ? this.layout : 'A'
if (this.activeTool) {
if (this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isCurrentTask && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState < 2) {
this.$nextTick(() => {
@ -2576,8 +2607,28 @@ export default {
// position: relative;
display: flex;
flex-direction: column;
transition: .5s;
position: relative;
}
.list_btn {
position: absolute;
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border: 1px solid #607d8b;
top: 0px;
left: -25px;
z-index: 99;
color: #d5d5d5;
background-color: #424242;
cursor: pointer;
}
.listHide {
width: 20px;
transition: .5s;
}
.form-wrapper{
flex-grow: 1;
height: 0;
@ -2713,5 +2764,20 @@ export default {
}
}
}
.listBox-leave-active,
.listBox-enter-active {
transition: all 0.5s ease;
}
.listBox-leave-active,
.listBox-enter {
// width: 0px !important;
flex-grow: 0 !important;
}
.listBox-leave,
.listBox-enter-active {
// width: 350px;
flex-grow: 1;
}
</style>

View File

@ -483,6 +483,21 @@ export default {
}
if (question.QuestionMark === 21) {
this.$set(this.questionForm, 'IntrahepaticLesion', this.questionForm[question.Id])
if (this.isCurrentTaskAdd === 'True') {
const lesionOrgan = this.getQuestionVal(5)
const lesionLength = this.getQuestionVal(0)
const measureData = this.questionForm['MeasureData']
if ((lesionOrgan === '肝脏' || lesionOrgan === 'Liver') && this.questionForm[question.Id]) {
if (!this.isBaseLineTask && (measureData.type === 'Length' && lesionLength >= 10)) {
const stateId = this.getQuestionId(7)
this.$set(this.questionForm, stateId, 0)
}
if (!this.isBaseLineTask && (measureData.type === 'Length' && lesionLength < 10)) {
const stateId = this.getQuestionId(7)
this.$set(this.questionForm, stateId, 1)
}
}
}
}
// saveTypeEnum 01访/2
if (this.questionForm.RowId) {
@ -831,7 +846,7 @@ export default {
loading.close()
return
}
console.log(lesionPart, measureData.type, lesionShort, '靶病灶部位为肝门淋巴结时选择要求时短轴≥2cm')
// console.log(lesionPart, measureData.type, lesionShort, '2cm')
if ((lesionPart === '肝门淋巴结' || lesionPart === 'Lymph node-hilum of liver') && !(measureData && measureData.type === 'Bidirectional' && lesionShort >= 20)) {
// 2cm
this.$confirm(this.$t('trials:mRecist:warnning:msg2'), {

View File

@ -1,65 +1,48 @@
<template>
<div class="dicom-container">
<div class="dicom-list">
<div :class="{ 'dicom-list': true, studyHide: !studyShow }">
<div class="container">
<div class="related-study-wrapper">
<div class="left">
<div class="visit-name-wrapper">
<div v-if="(visitTaskList.length > 0)" style="display: flex;flex-direction: row;">
<div
v-for="s in visitTaskList"
:key="s.VisitTaskId"
class="visit-item"
:class="{'visit-item-active': activeTaskVisitId==s.VisitTaskId}"
@click.prevent="handleClick(s)"
>{{ s.TaskBlindName }}</div>
<div v-for="s in visitTaskList" :key="s.VisitTaskId" class="visit-item"
:class="{ 'visit-item-active': activeTaskVisitId == s.VisitTaskId }" @click.prevent="handleClick(s)">
{{
s.TaskBlindName }}</div>
</div>
</div>
</div>
<div class="right">
<div
v-for="s in visitTaskList"
v-show="activeTaskVisitId === s.VisitTaskId"
:key="s.VisitTaskId"
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"
@previewNoneDicoms="previewNoneDicoms"
/>
</div>
<div class="study_btn" @click.stop="clickShow"
:title="studyShow ? $t('reading:dicom:dicom-list:hiden') : $t('reading:dicom:dicom-list:show')">
<i :class="studyShow ? 'el-icon-back' : 'el-icon-right'"></i>
</div>
<transition name="studyBox">
<div class="right" v-show="studyShow">
<div v-for="s in visitTaskList" v-show="activeTaskVisitId === s.VisitTaskId" :key="s.VisitTaskId"
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"
@previewNoneDicoms="previewNoneDicoms" />
</div>
</div>
</transition>
</div>
</div>
</div>
<div class="dicom-viewer">
<div class="container">
<DicomViewer
v-if="activeTaskVisitId"
ref="dicomViewer"
:is-show="isShow"
: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"
:is-reading-task-view-in-order="isReadingTaskViewInOrder"
:is-exists-manual="isExistsManual"
:iseCRFShowInDicomReading="iseCRFShowInDicomReading"
@previewCD="previewCD"
/>
<DicomViewer v-if="activeTaskVisitId" ref="dicomViewer" :is-show="isShow"
: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"
:is-reading-task-view-in-order="isReadingTaskViewInOrder" :is-exists-manual="isExistsManual"
:iseCRFShowInDicomReading="iseCRFShowInDicomReading" @previewCD="previewCD" />
</div>
</div>
@ -170,7 +153,8 @@ export default {
activeTaskIsBaseline: false,
activeTaskReadingTaskState: 2,
readingTaskState: 2,
open: null
open: null,
studyShow: true,
}
},
computed: {
@ -250,6 +234,12 @@ export default {
window.removeEventListener('beforeunload', e => { cornerstone.imageCache.purgeCache() })
},
methods: {
clickShow() {
this.studyShow = !this.studyShow
this.$nextTick(() => {
this.$refs.dicomViewer.changeLayout()
})
},
async getVisitInfo() {
const loading = this.$loading({ fullscreen: true })
@ -474,7 +464,7 @@ export default {
getSeriesInfoByMark(baseSeries, visitTaskId, obj, visitTaskIdx) {
var seriesInfo = null
if (obj) {
// ID
// ID
var index = visitTaskIdx
if (index > -1) {
var idx = -1
@ -533,7 +523,7 @@ export default {
}
</script>
<style lang="scss" scoped>
.dicom-container{
.dicom-container {
width: 100%;
height: 100%;
display: flex;
@ -542,32 +532,36 @@ export default {
background-color: #000;
box-sizing: border-box;
user-select: none;
::-webkit-scrollbar {
width: 5px;
height: 5px;
}
::-webkit-scrollbar-thumb {
border-radius: 10px;
background: #d0d0d0;
}
.dicom-viewer{
.dicom-viewer {
flex: 1;
width: 100%;
box-sizing: border-box;
.container{
.container {
width: 100%;
height: 100%;
box-sizing: border-box;
}
}
.dicom-list{
width: 200px;
padding: 5px 0px;
.dicom-list {
width: 200px;
transition: 0.5s;
padding: 5px 0px;
box-sizing: border-box;
.container{
.container {
width: 100%;
height: 100%;
box-sizing: border-box;
@ -575,7 +569,8 @@ export default {
// border: 1px solid #ccc;
}
/deep/.el-tabs{
/deep/.el-tabs {
box-sizing: border-box;
padding: 0 5px;
height: 100%;
@ -583,26 +578,31 @@ export default {
flex-direction: column;
// justify-content: flex-start;
border: 1px solid #727272;
.el-tabs__item{
.el-tabs__item {
color: #fff;
}
.el-tabs__header{
.el-tabs__header {
height: 55px;
margin:0px;
margin: 0px;
box-sizing: border-box;
}
.el-tabs__content{
.el-tabs__content {
flex: 1;
margin:0px;
margin: 0px;
overflow-y: auto;
box-sizing: border-box;
}
.el-tabs__item{
.el-tabs__item {
color: #fff;
}
}
.dicom-desc{
.dicom-desc {
font-weight: bold;
font-size: 13px;
text-align: center;
@ -610,23 +610,28 @@ export default {
color: #d0d0d0;
padding: 2px;
}
.ps {
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;
}
/deep/.el-progress__text{
/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;
@ -639,11 +644,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 {
@ -652,9 +659,11 @@ export default {
border: 2px solid #252525;
cursor: pointer;
}
.image-desc {
vertical-align: top;
p{
p {
width: 100px;
white-space: nowrap;
overflow: hidden;
@ -667,22 +676,40 @@ export default {
}
}
}
.related-study-wrapper{
.related-study-wrapper {
box-sizing: border-box;
height: 100%;
padding-bottom: 5px;
display: flex;
flex-direction: row;
justify-content: space-between;
position: relative;
.left{
.study_btn {
position: absolute;
width: 25px;
height: 25px;
line-height: 25px;
text-align: center;
border: 1px solid #607d8b;
top: 65px;
right: -25px;
z-index: 99;
color: #d5d5d5;
background-color: #424242;
cursor: pointer;
}
.left {
position: relative;
width: 25px;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
box-sizing: border-box;
.visit-name-wrapper{
.visit-name-wrapper {
position: absolute;
top: 5px;
@ -697,35 +724,59 @@ export default {
// flex-direction: row;
// align-content: flex-start;
}
.visit-item{
.visit-item {
margin-left: 10px;
white-space: nowrap;
padding: 0px 4px;
padding: 0px 4px;
border: 1px solid #999999;
border-bottom:none ;
border-bottom: none;
text-align: center;
background-color: #4e4e4e;
color: #d5d5d5;
cursor: pointer;
// margin-left: 10px;
}
.visit-item-active{
.visit-item-active {
background-color: #607d8b;
border: 1px solid #607d8b;
}
}
.right{
width:170px;
flex:1;
.right {
width: 170px;
flex: 1;
height: 100%;
border-left: 1px solid #4a4a4a;
color: #d5d5d5;
.study-wrapper{
.study-wrapper {
width: 100%;
height: 100%;
}
}
}
}
.studyHide {
width: 30px;
transition: 0.5s;
}
}
.studyBox-leave-active,
.studyBox-enter-active {
transition: all 0.5s ease;
}
.studyBox-leave-active,
.studyBox-enter {
width: 0px !important;
}
.studyBox-leave,
.studyBox-enter-active {
width: 170px;
}
</style>