2522 lines
95 KiB
Vue
2522 lines
95 KiB
Vue
<template>
|
|
<div class="dicom-viewer-wrapper">
|
|
<div class="dicom-viewer-container" style="position:relative">
|
|
<div class="dicom-tools">
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:layout')}`" placement="bottom">
|
|
<div class="tool-wrapper" @click.stop="showPanel($event)" @mouseleave="handleMouseout">
|
|
<div class="dropdown">
|
|
<div class="icon">
|
|
<svg-icon icon-class="layout" class="svg-icon" />
|
|
<i class="el-icon-arrow-down" style="color:#fff;" />
|
|
</div>
|
|
<!-- 布局 -->
|
|
<!-- <div class="text">{{ $t('trials:reading:button:layout') }}<i class="el-icon-caret-bottom" /></div> -->
|
|
<div class="dropdown-content layout-content">
|
|
<ul style="width:50px">
|
|
<li class="flex_row" @click.stop="changeLayout('A')">
|
|
<div class="layout_box_1_1">
|
|
A
|
|
</div>
|
|
</li>
|
|
<li class="flex_row" @click.stop="changeLayout('A|A')">
|
|
<div class="layout_box_1_1">
|
|
A
|
|
</div>
|
|
<div class="layout_box_1_1">
|
|
A
|
|
</div>
|
|
</li>
|
|
<li v-if="isReadingTaskViewInOrder === 1" class="flex_row" @click.stop="changeLayout('A|B')">
|
|
<div class="layout_box_1_1">
|
|
A
|
|
</div>
|
|
<div class="layout_box_1_1">
|
|
B
|
|
</div>
|
|
</li>
|
|
|
|
<li class="flex_column" @click.stop="changeLayout('A|A|A|A')">
|
|
|
|
<div style="flex:1;display: flex;width:100%;">
|
|
<div class="layout_box_1_2">
|
|
A
|
|
</div>
|
|
<div class="layout_box_1_2">
|
|
A
|
|
</div>
|
|
</div>
|
|
<div style="flex:1;display: flex;width:100%;">
|
|
<div class="layout_box_1_2">
|
|
A
|
|
</div>
|
|
<div class="layout_box_1_2">
|
|
A
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:wwwc')}`" placement="bottom">
|
|
<div class="tool-wrapper" @click.stop="showPanel($event)" @mouseleave="handleMouseout">
|
|
<div class="dropdown">
|
|
<div
|
|
class="icon"
|
|
data-tool="Wwwc"
|
|
:class="[activeTool==='Wwwc'?'tool_active':'']"
|
|
|
|
@click.prevent="setToolActive('Wwwc',false)"
|
|
>
|
|
<svg-icon icon-class="reverse" class="svg-icon" />
|
|
<i class="el-icon-arrow-down" style="color:#fff;" />
|
|
</div>
|
|
<!-- 调窗 -->
|
|
<!-- <div class="text">{{ $t('trials:reading:button:wwwc') }}<i class="el-icon-caret-bottom" /></div> -->
|
|
<div class="dropdown-content">
|
|
<ul style="width:165px;">
|
|
|
|
<li v-for="item in wwwcArr" :key="item.label">
|
|
<a href="#" @click.prevent="setDicomCanvasWwwc(item)">
|
|
<div v-if="item.wc !== null" style="display:flex;flex-direction: row;justify-content: space-between;">
|
|
<div>{{ item.label }}</div>
|
|
<div>{{ `${item.ww} / ${item.wc}` }}</div>
|
|
</div>
|
|
<div v-else style="text-align:left;">
|
|
{{ item.label }}
|
|
</div>
|
|
</a>
|
|
<!-- <div
|
|
v-if="item.val === 1"
|
|
class="divider"
|
|
>
|
|
W/L {{ $t('trials:reading:title:preset') }}
|
|
</div> -->
|
|
<el-divider v-if="item.val === 1" class="divider" content-position="center">{{ ` ${$t('trials:reading:title:preset') }` }}</el-divider>
|
|
</li>
|
|
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<!-- <div class="tool-wrapper">
|
|
|
|
<div
|
|
class="icon"
|
|
data-tool="WwwcRegion"
|
|
:class="[activeTool==='WwwcRegion'?'tool_active':'']"
|
|
|
|
@click.prevent="setToolActive('WwwcRegion',false)"
|
|
>
|
|
<svg-icon icon-class="wwwcRegion" class="svg-icon" />
|
|
</div>
|
|
<div class="text">区域调窗</div>
|
|
|
|
</div> -->
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:reverseColor')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
|
|
<div
|
|
class="icon"
|
|
:class="[activeTool==='reversecolor'?'tool_active':'']"
|
|
|
|
@click.prevent="toggleInvert"
|
|
>
|
|
<svg-icon icon-class="reversecolor" class="svg-icon" />
|
|
</div>
|
|
<!-- 反色 -->
|
|
<!-- <div class="text">{{ $t('trials:reading:button:reverseColor') }}</div> -->
|
|
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:zoom')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
:class="[activeTool==='Zoom'?'tool_active':'']"
|
|
data-tool="Zoom"
|
|
@click.prevent="setToolActive('Zoom',false)"
|
|
>
|
|
<svg-icon icon-class="magnifier" class="svg-icon" />
|
|
</div>
|
|
<!-- 缩放 -->
|
|
<div class="text">{{ $t('trials:reading:button:zoom') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:move')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
:class="[activeTool==='Pan'?'tool_active':'']"
|
|
data-tool="Pan"
|
|
@click.prevent="setToolActive('Pan',false)"
|
|
>
|
|
<svg-icon icon-class="move" class="svg-icon" />
|
|
</div>
|
|
<!-- 移动 -->
|
|
<div class="text">{{ $t('trials:reading:button:move') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:rotate')}`" placement="bottom">
|
|
<div class="tool-wrapper" @click.stop="showPanel($event)" @mouseleave="handleMouseout">
|
|
<!-- @click.prevent="setToolActive('Rotate',false)" -->
|
|
<div class="dropdown">
|
|
<div
|
|
class="icon"
|
|
data-tool="Rotate"
|
|
:class="[activeTool==='Rotate'?'tool_active':'']"
|
|
>
|
|
<svg-icon icon-class="rotate" class="svg-icon" />
|
|
<i class="el-icon-arrow-down" style="color:#fff;" />
|
|
</div>
|
|
<!-- 旋转 -->
|
|
<div class="text">{{ $t('trials:reading:button:rotate') }}<i class="el-icon-caret-bottom" /></div>
|
|
<div class="dropdown-content">
|
|
<ul style="width:100px;">
|
|
<li v-for="rotate in rotateArr" :key="rotate.label" style="text-align:left;">
|
|
<a href="#" @click.prevent="setDicomCanvasRotate(rotate.val)">{{ rotate.label }}</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="fitType===1?`${$t('trials:reading:button:fitWindow')}`:`${$t('trials:reading:button:fitImage')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
@click.prevent="fitToType(fitType===1?'fitToWindow':'fitToImage')"
|
|
>
|
|
<svg-icon v-if="fitType===1" icon-class="fitToWindow" class="svg-icon" />
|
|
<svg-icon v-else icon-class="fitToImage" class="svg-icon" />
|
|
</div>
|
|
<div class="text">{{ fitType===1?$t('trials:reading:button:fitWindow'):$t('trials:reading:button:fitImage') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:imageIndexSync')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
:class="[isScrollSync?'tool_active':'']"
|
|
@click.prevent="setImageIndexSync"
|
|
>
|
|
<i v-if="isScrollSync" class="el-icon-lock svg-icon" />
|
|
<i v-else class="el-icon-unlock svg-icon" />
|
|
</div>
|
|
<!-- 同步 -->
|
|
<div class="text">{{ $t('trials:reading:button:imageIndexSync') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
<!--
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
@click.prevent="fitToType('fitToImage')"
|
|
>
|
|
<svg-icon icon-class="fitToImage" class="svg-icon" />
|
|
</div>
|
|
<div class="text">适应图像</div>
|
|
</div> -->
|
|
<el-tooltip class="item" effect="dark" :content="`${$t('trials:reading:button:screenShot')}`" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
@click.prevent="saveImage"
|
|
>
|
|
<svg-icon icon-class="image" class="svg-icon" />
|
|
</div>
|
|
<!-- 截屏 -->
|
|
<div class="text">{{ $t('trials:reading:button:screenShot') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<div
|
|
v-for="tool in measuredTools"
|
|
:key="tool.toolName"
|
|
>
|
|
<el-tooltip class="item" effect="dark" placement="bottom">
|
|
<div slot="content">
|
|
<div v-if="tool.disabledReason">
|
|
<h4 style="margin:0;padding-bottom:2px;">{{ tool.text }}</h4>
|
|
<br>{{ tool.disabledReason }}
|
|
</div>
|
|
<div v-else>{{ tool.text }}</div>
|
|
|
|
</div>
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
:class="[activeTool===tool.toolName?'tool_active':'']"
|
|
:style="{cursor:tool.isDisabled?'not-allowed':'pointer'}"
|
|
:data-tool="tool.toolName"
|
|
@click.prevent="setToolActive(tool.toolName,true,$event)"
|
|
@mouseenter="enter($event,tool.toolName)"
|
|
>
|
|
<svg-icon :icon-class="tool.icon" class="svg-icon" />
|
|
</div>
|
|
<div class="text">{{ tool.text }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
<!-- <div v-else class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
:class="[activeTool===tool.toolName?'tool_active':'']"
|
|
:style="{cursor:tool.isDisabled?'not-allowed':'pointer'}"
|
|
:data-tool="tool.toolName"
|
|
@click.prevent="setToolActive(tool.toolName,true,$event)"
|
|
@mouseenter="enter($event,tool.toolName)"
|
|
>
|
|
<svg-icon :icon-class="tool.icon" class="svg-icon" />
|
|
</div>
|
|
<div class="text">{{ tool.text }}</div>
|
|
</div> -->
|
|
</div>
|
|
<el-tooltip v-if="CriterionType === 2 && studyList.length > 0" class="item" effect="dark" :content="$t('trials:lugano:button:fusion')" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
@click.prevent="handleFusion"
|
|
>
|
|
<svg-icon icon-class="fusion" class="svg-icon" />
|
|
</div>
|
|
<!-- 截屏 -->
|
|
<div class="text">{{ $t('trials:lugano:button:fusion') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
<div class="tool-frame">
|
|
<!-- 第一帧 -->
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicom-show:firstframe')" placement="bottom">
|
|
<div class="icon" @click.prevent="scrollPage(-99999)">
|
|
<svg-icon icon-class="firstframe" class="svg-icon" />
|
|
</div>
|
|
</el-tooltip>
|
|
<!-- 上一帧 -->
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicom-show:previousframe')" placement="bottom">
|
|
<div class="icon" @click.prevent="scrollPage(-1)">
|
|
<svg-icon icon-class="previousframe" class="svg-icon" />
|
|
</div>
|
|
</el-tooltip>
|
|
<!-- 播放/暂停 -->
|
|
<el-tooltip class="item" effect="dark" :content="clipPlaying?$t('trials:dicom-show:stop'):$t('trials:dicom-show:play')" placement="bottom">
|
|
<div v-if="clipPlaying" class="icon" @click.prevent="toggleClipPlay(false)">
|
|
<svg-icon icon-class="stop" class="svg-icon" />
|
|
</div>
|
|
<div v-else class="icon" @click.prevent="toggleClipPlay(true)">
|
|
<svg-icon icon-class="play" class="svg-icon" />
|
|
</div>
|
|
</el-tooltip>
|
|
<!-- 下一帧 -->
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicom-show:nextframe')" placement="bottom">
|
|
<div class="icon" @click.prevent="scrollPage(1)">
|
|
<svg-icon icon-class="nextframe" class="svg-icon" />
|
|
</div>
|
|
</el-tooltip>
|
|
<!-- 最后一帧 -->
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicom-show:lastframe')" placement="bottom">
|
|
<div class="icon" @click.prevent="scrollPage(99999)">
|
|
<svg-icon icon-class="lastframe" class="svg-icon" />
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:dicom-show:speed')" placement="bottom">
|
|
<select v-model="fps" class="select-wrapper" :disabled="clipPlaying" @change="setDicomCanvasfps($event)">
|
|
<!-- 默认值 -->
|
|
<!-- <option :value="5">{{ $t('trials:dicom-show:default') }}</option> -->
|
|
<option :value="5">5</option>
|
|
<option :value="10">10</option>
|
|
<option :value="15">15</option>
|
|
<option :value="20">20</option>
|
|
<option :value="25">25</option>
|
|
<option :value="30">30</option>
|
|
</select>
|
|
</el-tooltip>
|
|
</div>
|
|
|
|
<el-tooltip class="item" effect="dark" :content="$t('trials:reading:button:reset')" placement="bottom">
|
|
<div class="tool-wrapper">
|
|
<div
|
|
class="icon"
|
|
@click.prevent="resetViewport"
|
|
>
|
|
<svg-icon icon-class="refresh" class="svg-icon" />
|
|
</div>
|
|
<div class="text">{{ $t('trials:reading:button:reset') }}</div>
|
|
</div>
|
|
</el-tooltip>
|
|
|
|
<div style="margin-left:auto;">
|
|
<div style="padding:5px">
|
|
<!-- 手册 -->
|
|
<el-button v-if="isExistsManual" type="text" @click="previewManuals">{{ $t('trials:reading:button:handbooks') }}</el-button>
|
|
<!-- 临床数据 -->
|
|
<el-button v-if="isExistsClinicalData" type="text" @click="previewCD">{{ $t('trials:reading:button:clinicalData') }}</el-button>
|
|
<!-- 个性化配置 -->
|
|
<el-button type="text" @click="previewConfig">{{ $t('trials:reading:button:customCfg') }}</el-button>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
<div class="dicom-viewers">
|
|
<div ref="container" class="viewer-container" :class="['box', `box_${layoutRow}_${layoutCol}`]">
|
|
<div
|
|
v-for="i in maxCanvas"
|
|
:key="i"
|
|
:class="['item', i-1===currentDicomCanvasIndex?'item_active':'']"
|
|
:data-index="i-1"
|
|
:style="i-1===currentDicomCanvasIndex ? cornerstoneStyle : {}"
|
|
@click="activateDicomCanvas(i-1)"
|
|
>
|
|
<dicom-canvas
|
|
v-if="canvasW"
|
|
:ref="`dicomCanvas${i-1}`"
|
|
:style="{width:canvasW,height: canvasH}"
|
|
:canvas-index="i-1"
|
|
:is-active="i-1===currentDicomCanvasIndex"
|
|
:is-scroll-sync="isScrollSync"
|
|
:is-reading-show-subject-info="isReadingShowSubjectInfo"
|
|
:is-reading-task-view-in-order="isReadingTaskViewInOrder"
|
|
:current-dicom-canvas-index="currentDicomCanvasIndex"
|
|
:custom-wwc-tpl="customWwcTpl"
|
|
:data-canvas-uid="`dicomCanvas${i-1}`"
|
|
@setCornerstoneStyle="setCornerstoneStyle(i-1)"
|
|
@setMeasureData="setMeasureData"
|
|
@modifyMeasureData="modifyMeasureData"
|
|
@scrollSync="scrollSync"
|
|
@selectViewCanvas="selectViewCanvas"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div ref="form-container" class="form-container">
|
|
<!-- 激活canvas测量数据 -->
|
|
|
|
<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 !== 17"
|
|
ref="measurementList"
|
|
:question-form-change-state="questionFormChangeState"
|
|
:question-form-change-num="questionFormChangeNum"
|
|
:is-show="isShow"
|
|
:is-reading-show-subject-info="isReadingShowSubjectInfo"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- <div v-if="petct.visible" class="petct_wrapper">
|
|
<PetCt
|
|
:is-reading-show-subject-info="isReadingShowSubjectInfo"
|
|
@close="petct.visible = false"
|
|
/>
|
|
</div> -->
|
|
</div>
|
|
|
|
<el-dialog
|
|
v-if="customWwc.visible"
|
|
:visible.sync="customWwc.visible"
|
|
:close-on-click-modal="false"
|
|
:title="customWwc.title"
|
|
width="400px"
|
|
custom-class="base-dialog-wrapper"
|
|
>
|
|
<CustomWwwcForm :ww="activeCanvasWW" :wc="activeCanvasWC" @close="customWwc.visible = false" @setWwwc="setWwwc" />
|
|
</el-dialog>
|
|
|
|
<el-dialog
|
|
v-if="personalConfigDialog.visible"
|
|
:visible.sync="personalConfigDialog.visible"
|
|
:close-on-click-modal="false"
|
|
:title="personalConfigDialog.title"
|
|
width="600px"
|
|
>
|
|
<el-tabs v-model="activeName" class="personal_config">
|
|
<!-- 热键 -->
|
|
<el-tab-pane :label="$t('trials:reading:tab:hotkeys')" name="1">
|
|
<Hotkeys v-if="activeName === '1'" :reading-tool="0" @reset="resetHotkeyList" />
|
|
</el-tab-pane>
|
|
<!-- W/L模板 -->
|
|
<el-tab-pane :label="$t('trials:reading:tab:wlTemplate')" name="2">
|
|
<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'" />
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
|
|
</el-dialog>
|
|
|
|
<el-dialog
|
|
v-if="manualsDialog.visible"
|
|
:visible.sync="manualsDialog.visible"
|
|
:custom-class="isFullscreen?'manuals-full-dialog-container':'manuals-dialog-container'"
|
|
:show-close="false"
|
|
:close-on-click-modal="false"
|
|
:fullscreen="isFullscreen"
|
|
>
|
|
<span slot="title" class="dialog-footer">
|
|
<!-- 手册 -->
|
|
<span>{{ $t('trials:reading:button:handbooks') }}</span>
|
|
<span style="position: absolute;right: 20px;font-size: 20px;">
|
|
<svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" style="margin-right:10px;cursor: pointer;" @click="isFullscreen=!isFullscreen" />
|
|
<svg-icon icon-class="close" style="cursor: pointer;" @click="manualsDialog.visible = false" />
|
|
</span>
|
|
</span>
|
|
<div style="height: 100%;margin:0;">
|
|
<Manuals :trial-id="trialId" />
|
|
</div>
|
|
</el-dialog>
|
|
|
|
<el-dialog
|
|
v-if="fusionSeries.visible"
|
|
:visible.sync="fusionSeries.visible"
|
|
:close-on-click-modal="false"
|
|
:title="$t('trials:lugano:dialogTitle:fusion') "
|
|
width="850px"
|
|
>
|
|
<el-form ref="fusionForm" :model="fusionForm" label-width="120px" label-position="left">
|
|
<!-- 任务名称 -->
|
|
<el-form-item
|
|
:label="$t('trials:lugano:fusionDialog:label:taskBlindName')"
|
|
prop="taskBlindName"
|
|
>
|
|
<el-input
|
|
v-model="fusionForm.taskBlindName"
|
|
:disabled="true"
|
|
style="width:200px"
|
|
/>
|
|
</el-form-item>
|
|
<!-- 检查 -->
|
|
<el-form-item
|
|
:label="$t('trials:lugano:fusionDialog:label:study')"
|
|
prop="studyID"
|
|
:rules="[
|
|
{ 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-select>
|
|
</el-form-item>
|
|
<!-- 融合图像 -->
|
|
<label style="color: #dfdfdf;line-height: 36px;vertical-align: middle;font-size: 14px;">{{ $t('trials:lugano:fusionDialog:label:fusionImages') }}</label>
|
|
<div style="display: flex;flex-direction: row;justify-content: space-between;margin-bottom:10px;" class="series-table">
|
|
|
|
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
|
|
<!-- CT/MRI序列 -->
|
|
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ctSeries') }}</h3>
|
|
<el-table
|
|
ref="ctSeries"
|
|
:data="ctSeries"
|
|
:show-header="false"
|
|
style="width: 380px"
|
|
size="mini"
|
|
height="300"
|
|
:default-sort="{prop: 'instanceCount', order: 'descending'}"
|
|
@selection-change="handleCTSelectionChange"
|
|
@select="handleCTSelect"
|
|
>
|
|
|
|
<el-table-column
|
|
type="selection"
|
|
width="30"
|
|
/>
|
|
<el-table-column
|
|
label=""
|
|
width="100"
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-image
|
|
style="width: 60px; height: 60px"
|
|
:src="scope.row.previewImageUrl"
|
|
fit="fit"
|
|
crossorigin="anonymous"
|
|
/>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label=""
|
|
min-width="50"
|
|
show-overflow-tooltip
|
|
>
|
|
<template slot-scope="scope">
|
|
<div>#{{ scope.row.seriesNumber }} </div>
|
|
<div>{{ scope.row.modality }}: {{ scope.row.instanceCount }} images T: {{ parseFloat(scope.row.sliceThickness).toFixed(digitPlaces) }}</div>
|
|
<div>{{ scope.row.description }}</div>
|
|
</template>
|
|
</el-table-column>
|
|
|
|
</el-table>
|
|
</div>
|
|
|
|
<div style="border: 1px solid #5e5e5e;border-radius: 5px;padding: 0 10px;">
|
|
<!-- PET序列 -->
|
|
<h3 style="color:#ddd">{{ $t('trials:lugano:fusionDialog:label:ptSeries') }}</h3>
|
|
<el-table
|
|
ref="petSeries"
|
|
:data="petSeries"
|
|
:show-header="false"
|
|
style="width: 380px"
|
|
size="mini"
|
|
height="300"
|
|
@selection-change="handlePTSelectionChange"
|
|
@select="handlePTSelect"
|
|
>
|
|
<el-table-column
|
|
type="selection"
|
|
width="30"
|
|
/>
|
|
<el-table-column
|
|
label=""
|
|
width="100"
|
|
>
|
|
<template slot-scope="scope">
|
|
<el-image
|
|
style="width: 60px; height: 60px"
|
|
:src="scope.row.previewImageUrl"
|
|
fit="fit"
|
|
crossorigin="anonymous"
|
|
/>
|
|
</template>
|
|
</el-table-column>
|
|
<el-table-column
|
|
label=""
|
|
min-width="50"
|
|
show-overflow-tooltip
|
|
>
|
|
<template slot-scope="scope">
|
|
<div>#{{ scope.row.seriesNumber }} </div>
|
|
<div>{{ scope.row.modality }}: {{ scope.row.instanceCount }} images T: {{ parseFloat(scope.row.sliceThickness).toFixed(digitPlaces) }}</div>
|
|
<div>{{ scope.row.description }}</div>
|
|
</template>
|
|
</el-table-column>
|
|
</el-table>
|
|
</div>
|
|
</div>
|
|
<el-form-item style="text-align:right;">
|
|
<!-- 取消 -->
|
|
<el-button size="mini" @click="fusionSeries.visible = false">{{ $t('common:button:cancel') }}</el-button>
|
|
<!-- 确认 -->
|
|
<el-button
|
|
type="primary"
|
|
size="mini"
|
|
@click="handleSubmitFusionSeries"
|
|
>
|
|
{{ $t('common:button:confirm') }}</el-button>
|
|
</el-form-item>
|
|
</el-form>
|
|
</el-dialog>
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import * as cornerstone from 'cornerstone-core'
|
|
import * as cornerstoneMath from 'cornerstone-math'
|
|
import * as cornerstoneTools from 'cornerstone-tools'
|
|
import Hammer from 'hammerjs'
|
|
cornerstoneTools.external.cornerstone = cornerstone
|
|
cornerstoneTools.external.Hammer = Hammer
|
|
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
|
|
import { getDoctorShortcutKey, getUserWLTemplateList } from '@/api/user'
|
|
import { mapGetters } from 'vuex'
|
|
import store from '@/store'
|
|
import { getToken } from '@/utils/auth'
|
|
// import DicomCanvas from './DicomCanvas'
|
|
// import PetCt from './Fusion/PetCt'
|
|
import DicomCanvas from '@/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue'
|
|
import RecistQuestionList from './Recist/QuestionList'
|
|
import RecistBMQuestionList from './RecistBM/QuestionList'
|
|
import IRecistQuestionList from './IRecist/QuestionList'
|
|
import PCWGQuestionList from './PCWG/QuestionList'
|
|
import LuganoQuestionList from './Lugano/QuestionList'
|
|
import CustomWwwcForm from './CustomWwwcForm'
|
|
import Manuals from './Manuals'
|
|
import Hotkeys from './Hotkeys'
|
|
import WL from './WL'
|
|
import Others from './Others'
|
|
import DicomEvent from './DicomEvent'
|
|
import html2canvas from 'html2canvas'
|
|
export default {
|
|
name: 'DicomViewer',
|
|
components: {
|
|
// PetCt,
|
|
DicomCanvas,
|
|
CustomWwwcForm,
|
|
Manuals,
|
|
Hotkeys,
|
|
WL,
|
|
Others,
|
|
RecistQuestionList,
|
|
PCWGQuestionList,
|
|
RecistBMQuestionList,
|
|
IRecistQuestionList,
|
|
LuganoQuestionList },
|
|
props: {
|
|
isShow: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isExistsClinicalData: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isExistsNoDicomFile: {
|
|
type: Boolean,
|
|
default: false
|
|
},
|
|
isReadingShowSubjectInfo: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
isReadingTaskViewInOrder: {
|
|
type: Number,
|
|
required: true
|
|
},
|
|
isExistsManual: {
|
|
type: Boolean,
|
|
required: true
|
|
},
|
|
questionFormChangeState: {
|
|
type: Boolean,
|
|
default() {
|
|
return false
|
|
}
|
|
},
|
|
questionFormChangeNum: {
|
|
type: Number,
|
|
default() {
|
|
return 0
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
cornerstoneStyle: {},
|
|
layouts: [
|
|
{ index: 0, row: 1, col: 1, name: 'A' },
|
|
{ index: 1, row: 1, col: 2, name: 'A|A' },
|
|
{ index: 2, row: 1, col: 2, name: 'A|B' },
|
|
{ index: 3, row: 2, col: 2, name: 'A|A|A|A' }
|
|
// { index: 2, row: 2, col: 1 },
|
|
// { index: 3, row: 2, col: 2 }
|
|
],
|
|
rotateArr: [
|
|
{ label: this.$t('trials:reading:button:rotateDefault'), val: 1 }, // 默认值
|
|
{ label: this.$t('trials:reading:button:rotateVertical'), val: 2 }, // 垂直翻转
|
|
{ label: this.$t('trials:reading:button:rotateHorizontal'), val: 3 }, // 水平翻转
|
|
{ label: this.$t('trials:reading:button:rotateTurnLeft'), val: 4 }, // 左转90度
|
|
{ label: this.$t('trials:reading:button:rotateTurnRight'), val: 5 }// 右转90度
|
|
],
|
|
maxCanvas: 1,
|
|
layoutRow: 1,
|
|
layoutCol: 1,
|
|
currentDicomCanvasIndex: 0,
|
|
currentDicomCanvas: {
|
|
toolState: {
|
|
clipPlaying: false
|
|
}
|
|
},
|
|
colormapsList: [],
|
|
rotateList: [],
|
|
colorList: [],
|
|
wwwcList: [],
|
|
canvasW: null,
|
|
canvasH: null,
|
|
activeTool: '',
|
|
CriterionType: 0,
|
|
measuredTools: [
|
|
// 直径测量
|
|
{ toolName: 'Length', text: this.$t('trials:reading:button:length'), icon: 'length', isDisabled: false, disabledReason: '' },
|
|
// 长短径测量
|
|
{ toolName: 'Bidirectional', text: this.$t('trials:reading:button:bidirectional'), icon: 'bidirection', isDisabled: false, disabledReason: '' },
|
|
// 矩形工具
|
|
{ toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' },
|
|
// 箭头工具
|
|
{ toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }
|
|
|
|
],
|
|
fitType: 0,
|
|
isDisabledTool: false,
|
|
canvasObj: {},
|
|
wwwcArr: [],
|
|
defaultWwwc: [
|
|
{ label: this.$t('trials:reading:button:wwwcDefault'), val: -1, ww: null, wc: null }, // 默认值
|
|
{ label: this.$t('trials:reading:button:wwwcCustom'), val: 0, ww: null, wc: null }, // 自定义
|
|
{ label: this.$t('trials:reading:button:wwwcRegion'), val: 1, ww: null, wc: null }, // 区域窗宽
|
|
{ label: 'CT Brain', wc: 40, ww: 80 },
|
|
{ label: 'CT Lungs', wc: -400, ww: 1500 },
|
|
{ label: 'CT Abdomen', wc: 60, ww: 400 },
|
|
{ label: 'CT Liver', wc: 40, ww: 400 },
|
|
{ label: 'CT Bone', wc: 300, ww: 1500 },
|
|
{ label: 'CT Bone1', wc: 0, ww: 0 }
|
|
|
|
],
|
|
activeSeries: {},
|
|
seriesStack: [],
|
|
trialId: '',
|
|
isScrollSync: false,
|
|
imageIndexSync: {
|
|
sourceCanvas: '',
|
|
targetCanvas: []
|
|
},
|
|
isFirstRender: false,
|
|
customWwc: { visible: false, title: null }, // 自定义调窗
|
|
personalConfigDialog: { visible: false, title: this.$t('trials:reading:button:customCfg') }, // 个性化配置
|
|
layout: '',
|
|
isFirstNotLinked: false,
|
|
hotKeyList: [],
|
|
activeName: '1',
|
|
customWwcTpl: [],
|
|
isFullscreen: false,
|
|
manualsDialog: { visible: false },
|
|
petct: { visible: false },
|
|
fusionSeries: { visible: false },
|
|
fusionForm: {
|
|
studyID: '',
|
|
visitTaskId: '',
|
|
readingTaskState: 2,
|
|
taskBlindName: '',
|
|
subjectCode: '',
|
|
isBaseLineTask: null,
|
|
isCurrentTask: null
|
|
},
|
|
ctSeriesInfo: {},
|
|
petSeriesInfo: {},
|
|
ctSeries: [],
|
|
petSeries: [],
|
|
petctWindow: null,
|
|
studyList: [],
|
|
digitPlaces: 2,
|
|
activeCanvasWW: null,
|
|
activeCanvasWC: null,
|
|
activeTaskInfo: {},
|
|
clipPlaying: false,
|
|
fps: 15
|
|
}
|
|
},
|
|
|
|
computed: {
|
|
...mapGetters(['visitTaskList', 'currentReadingTaskState', 'lastCanvasTaskId', 'imageQualityIssues'])
|
|
},
|
|
watch: {
|
|
currentReadingTaskState: {
|
|
immediate: true,
|
|
handler(val) {
|
|
if (val && this.currentDicomCanvasIndex && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`]) {
|
|
this.canvasObj[this.currentDicomCanvasIndex].readingTaskState = val
|
|
if (this.activeTool) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
this.activeTool = ''
|
|
}
|
|
}
|
|
}
|
|
},
|
|
lastCanvasTaskId: {
|
|
immediate: true,
|
|
handler(v) {
|
|
// if (v) {
|
|
// console.log('lastCanvasTaskId')
|
|
// const i = this.visitTaskList.findIndex(i => i.VisitTaskId === v)
|
|
// if (i < 0) return
|
|
// var studyList = this.visitTaskList[i].StudyList || []
|
|
// studyList = studyList.filter(i => !i.IsCriticalSequence && i.Modalities.indexOf('CT') !== -1 && i.Modalities.indexOf('PT') !== -1)
|
|
// if (studyList.length === 0) return
|
|
// this.studyList = studyList
|
|
// } else {
|
|
// this.studyList = []
|
|
// }
|
|
}
|
|
},
|
|
activeSeries: {
|
|
immediate: true,
|
|
handler(v) {
|
|
console.log('activeSeries', v)
|
|
if (v && v.isCurrentTask && this.studyList.length === 0) {
|
|
this.activeTaskInfo.taskName = v.taskBlindName
|
|
this.activeTaskInfo.visitTaskId = v.visitTaskId
|
|
const i = this.visitTaskList.findIndex(i => i.VisitTaskId === v.visitTaskId)
|
|
if (i < 0) return
|
|
this.activeTaskInfo.visitTaskIndex = i
|
|
var studyList = this.visitTaskList[i].StudyList || []
|
|
studyList = studyList.filter(i => !i.IsCriticalSequence && i.Modalities.indexOf('CT') !== -1 && i.Modalities.indexOf('PT') !== -1)
|
|
if (studyList.length === 0) return
|
|
this.studyList = studyList
|
|
}
|
|
}
|
|
},
|
|
imageQualityIssues: {
|
|
immediate: true,
|
|
handler(v) {}
|
|
},
|
|
currentDicomCanvasIndex: {
|
|
immediate: true,
|
|
handler(v) {
|
|
if (this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`] && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0]) {
|
|
this.clipPlaying = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toolState.clipPlaying
|
|
} else {
|
|
this.clipPlaying = false
|
|
this.fps = 15
|
|
}
|
|
}
|
|
}
|
|
|
|
},
|
|
mounted() {
|
|
this.getHotKeys()
|
|
this.getWwcTpl()
|
|
// cornerstone.imageCache.setMaximumSizeBytes(0)
|
|
|
|
// const maximumSizeInBytes = 1024 * 1024 * 1024 // 1 GB
|
|
// // const maximumSizeInBytes = 1024 * 1024 * 500
|
|
// cornerstone.imageCache.setMaximumSizeBytes(maximumSizeInBytes)
|
|
this.customWwc = { visible: false, title: this.$t('trials:reading:dagTitle:wwwcCustom') }
|
|
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
|
|
if (this.CriterionType === 10) {
|
|
this.measuredTools = [{ toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }]
|
|
} else if (this.CriterionType === 17) {
|
|
this.measuredTools = [{ toolName: 'Length', text: this.$t('trials:reading:button:length'), icon: 'length', isDisabled: false, disabledReason: '' }, { toolName: 'RectangleRoi', text: this.$t('trials:reading:button:rectangle'), icon: 'rectangle', isDisabled: false, disabledReason: '' }, { toolName: 'ArrowAnnotate', text: this.$t('trials:reading:button:arrowAnnotate'), icon: 'arrow', isDisabled: false, disabledReason: '' }]
|
|
}
|
|
this.rotateList[0] = '1'
|
|
this.colorList[0] = ''
|
|
this.wwwcList[0] = '1'
|
|
this.colormapsList = cornerstone.colors.getColormapsList()
|
|
this.currentDicomCanvas = this.$refs['dicomCanvas0'] ? this.$refs['dicomCanvas0'][0] : ''
|
|
this.trialId = this.$router.currentRoute.query.trialId
|
|
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
|
this.setCanvasStyle()
|
|
window.addEventListener('resize', this.setCanvasStyle)
|
|
DicomEvent.$on('updateImage', (instanceId) => {
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
var stack = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack
|
|
if (stack.studyId) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].updateImage(instanceId)
|
|
}
|
|
}
|
|
})
|
|
DicomEvent.$on('getMeasureData', () => {
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
var stack = this.$refs[`dicomCanvas${i}`][0].stack
|
|
if (stack.visitTaskId) {
|
|
this.$refs[`dicomCanvas${i}`][0].getMeasureData()
|
|
}
|
|
}
|
|
console.log('getMeasureData')
|
|
})
|
|
DicomEvent.$on('getScreenshots', async(measuredData, callback) => {
|
|
if (this.currentDicomCanvasIndex > -1) {
|
|
await this.imageLocation(measuredData)
|
|
if (!measuredData.isMarked) {
|
|
callback()
|
|
return
|
|
}
|
|
setTimeout(async() => {
|
|
// var base64Str = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getScreenshots()
|
|
const divForDownloadViewport = document.querySelector(
|
|
`div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]`
|
|
)
|
|
var canvas = await html2canvas(divForDownloadViewport)
|
|
var base64Str = canvas.toDataURL('image/png', 1)
|
|
console.log('getScreenshots')
|
|
callback(base64Str)
|
|
}, 50)
|
|
}
|
|
})
|
|
DicomEvent.$on('imageLocation', async(measuredData) => {
|
|
return new Promise(async resolve => {
|
|
if (!measuredData) return
|
|
await this.imageLocation(measuredData)
|
|
|
|
console.log('imageLocation')
|
|
resolve()
|
|
})
|
|
})
|
|
// DicomEvent.$on('imageLocation', async(measuredData, callback) => {
|
|
// if (measuredData) {
|
|
// await this.imageLocation(measuredData)
|
|
// }
|
|
// console.log('imageLocation')
|
|
// this.$nextTick(() => {
|
|
// if (callback) {
|
|
// callback()
|
|
// }
|
|
// })
|
|
// })
|
|
// DicomEvent.$on('imageLocation', measuredData => {
|
|
// if (!measuredData) return
|
|
// this.imageLocation(measuredData)
|
|
|
|
// console.log('imageLocation')
|
|
// })
|
|
DicomEvent.$on('setReadingState', readingTaskState => {
|
|
this.canvasObj[this.currentDicomCanvasIndex].readingTaskState = readingTaskState
|
|
if (this.activeTool) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
this.activeTool = ''
|
|
}
|
|
})
|
|
DicomEvent.$on('PGWC3Active', res => {
|
|
this.setToolActive('ArrowAnnotate', true, null, 'open')
|
|
})
|
|
DicomEvent.$on('loadImageStacks', seriesList => {
|
|
this.loadImageStacks(seriesList)
|
|
console.log('loadImageStacks')
|
|
})
|
|
DicomEvent.$on('loadLinkedImageStack', seriesInfo => {
|
|
this.loadLinkedImageStack(seriesInfo)
|
|
console.log('loadLinkedImageStack')
|
|
})
|
|
DicomEvent.$on('setMeasuredToolsPassive', () => {
|
|
this.setMeasuredToolsPassive()
|
|
})
|
|
DicomEvent.$on('readingPageUpdate', (data) => {
|
|
if (!this.petctWindow) return
|
|
this.petctWindow.postMessage({ type: 'readingPageUpdate', data: data }, window.location)
|
|
})
|
|
DicomEvent.$on('setReadingState', (data) => {
|
|
if (!this.petctWindow) return
|
|
this.petctWindow.postMessage({ type: 'setReadingState', data: data }, window.location)
|
|
})
|
|
DicomEvent.$on('closePetct', () => {
|
|
if (this.petctWindow) {
|
|
this.petctWindow.close()
|
|
}
|
|
})
|
|
window.addEventListener('beforeunload', () => {
|
|
if (this.petctWindow) {
|
|
this.petctWindow.close()
|
|
}
|
|
})
|
|
},
|
|
beforeDestroy() {
|
|
DicomEvent.$off('updateImage')
|
|
DicomEvent.$off('getMeasureData')
|
|
DicomEvent.$off('imageLocation')
|
|
DicomEvent.$off('setReadingState')
|
|
DicomEvent.$off('loadImageStacks')
|
|
DicomEvent.$off('loadLinkedImageStack')
|
|
DicomEvent.$off('setMeasuredToolsPassive')
|
|
DicomEvent.$off('readingPageUpdate')
|
|
DicomEvent.$off('setReadingState')
|
|
DicomEvent.$off('reload')
|
|
DicomEvent.$off('closePetct')
|
|
if (this.petctWindow) {
|
|
this.petctWindow.close()
|
|
}
|
|
window.removeEventListener('beforeunload', () => {
|
|
if (this.petctWindow) {
|
|
this.petctWindow.close()
|
|
}
|
|
})
|
|
},
|
|
methods: {
|
|
getWwcTpl() {
|
|
const loading = this.$loading({ fullscreen: true })
|
|
getUserWLTemplateList().then(res => {
|
|
this.customWwcTpl = []
|
|
res.Result.map(i => {
|
|
this.customWwcTpl.push({ label: i.TemplateName, wc: i.WL, ww: i.WW })
|
|
})
|
|
this.wwwcArr = [...this.defaultWwwc, ...this.customWwcTpl]
|
|
loading.close()
|
|
}).catch(() => { loading.close() })
|
|
},
|
|
getHotKeys() {
|
|
const loading = this.$loading({ fullscreen: true })
|
|
getDoctorShortcutKey({ imageToolType: 0 }).then(res => {
|
|
res.Result.map(item => {
|
|
this.hotKeyList.push({ id: item.Id, altKey: item.AltKey, ctrlKey: item.CtrlKey, shiftKey: item.ShiftKey, metaKey: item.MetaKey, key: item.Keyboardkey, code: item.Code, text: item.Text, shortcutKeyEnum: item.ShortcutKeyEnum })
|
|
})
|
|
this.bindHotKey()
|
|
loading.close()
|
|
}).catch(() => {
|
|
loading.close()
|
|
})
|
|
},
|
|
resetHotkeyList(arr) {
|
|
this.hotKeyList = []
|
|
|
|
arr.map(item => {
|
|
this.hotKeyList.push({ id: item.id, altKey: item.keys.controlKey.altKey, ctrlKey: item.keys.controlKey.ctrlKey, shiftKey: item.keys.controlKey.shiftKey, metaKey: item.keys.controlKey.metaKey, key: item.keys.controlKey.key, code: item.keys.controlKey.code, text: item.keys.text, shortcutKeyEnum: item.label })
|
|
})
|
|
|
|
// const loading = this.$loading({ fullscreen: true })
|
|
// getDoctorShortcutKey({ imageToolType: 0 }).then(res => {
|
|
// res.Result.map(item => {
|
|
// this.hotKeyList.push({ id: item.Id, altKey: item.AltKey, ctrlKey: item.CtrlKey, shiftKey: item.ShiftKey, metaKey: item.MetaKey, key: item.Keyboardkey, code: item.Code, text: item.Text, shortcutKeyEnum: item.ShortcutKeyEnum })
|
|
// })
|
|
// loading.close()
|
|
// }).catch(() => {
|
|
// loading.close()
|
|
// })
|
|
},
|
|
bindHotKey() {
|
|
var container = this.$refs['container']
|
|
// window.addEventListener
|
|
container.addEventListener('keydown', event => {
|
|
console.log(event)
|
|
event.preventDefault()
|
|
|
|
var idx = this.hotKeyList.findIndex(i => i.code === event.code && i.ctrlKey === event.ctrlKey && i.shiftKey === event.shiftKey && i.altKey === event.altKey)
|
|
if (idx === -1) return
|
|
var shortcutKeyEnum = this.hotKeyList[idx].shortcutKeyEnum
|
|
|
|
if (shortcutKeyEnum === 1) {
|
|
// 前一图像视口
|
|
this.selectViewCanvas(-1)
|
|
} else if (shortcutKeyEnum === 2) {
|
|
// 后一图像视口
|
|
this.selectViewCanvas(1)
|
|
} else if (shortcutKeyEnum === 3) {
|
|
// 上一个序列
|
|
const series = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].series
|
|
DicomEvent.$emit('selectSeries', { seriesId: series.seriesId, studyId: series.studyId, offset: -1 })
|
|
} else if (shortcutKeyEnum === 4) {
|
|
// 下一个序列
|
|
const series = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].series
|
|
DicomEvent.$emit('selectSeries', { seriesId: series.seriesId, studyId: series.studyId, offset: 1 })
|
|
} else if (shortcutKeyEnum === 5) {
|
|
// 上一张图像
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].scrollPage(-1)
|
|
} else if (shortcutKeyEnum === 6) {
|
|
// 下一张图像
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].scrollPage(1)
|
|
} else if (shortcutKeyEnum === 7) {
|
|
// 向左旋转
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, -90, 4)
|
|
} else if (shortcutKeyEnum === 8) {
|
|
// 向右旋转
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, 90, 5)
|
|
} else if (shortcutKeyEnum === 9) {
|
|
// 水平翻转
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(true, false, 0, 3)
|
|
} else if (shortcutKeyEnum === 10) {
|
|
// 垂直翻转
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, true, 0, 2)
|
|
} else if (shortcutKeyEnum === 11) {
|
|
// 放大
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setZoomScale(1)
|
|
} else if (shortcutKeyEnum === 12) {
|
|
// 缩小
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setZoomScale(0)
|
|
} else if (shortcutKeyEnum === 13) {
|
|
// 适应图像
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToImage()
|
|
} else if (shortcutKeyEnum === 14) {
|
|
// 适应窗口
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToWindow()
|
|
} else if (shortcutKeyEnum === 15) {
|
|
// 截图
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].saveImage()
|
|
} else if (shortcutKeyEnum === 16) {
|
|
// 反色
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
|
|
} else if (shortcutKeyEnum === 17) {
|
|
// 窗宽/窗位
|
|
var wwwcArrIdx = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].wwwcArrIdx
|
|
var wwwcArr = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].wwwcArr
|
|
if (wwwcArrIdx + 1 === wwwcArr.length) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].wwwcArrIdx = 0
|
|
} else {
|
|
++this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].wwwcArrIdx
|
|
}
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setWwwc(wwwcArr[wwwcArrIdx].ww, wwwcArr[wwwcArrIdx].wc)
|
|
} else if (shortcutKeyEnum === 18) {
|
|
// 重置
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetViewport()
|
|
} else if (shortcutKeyEnum === 19) {
|
|
// 显示或隐藏标记
|
|
if (this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState < 2) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setMeasureDataVisible()
|
|
}
|
|
}
|
|
})
|
|
},
|
|
resetViewport() {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetViewport()
|
|
},
|
|
previewConfig() {
|
|
this.activeName = '1'
|
|
this.personalConfigDialog.visible = true
|
|
},
|
|
setCornerstoneStyle(i) {
|
|
if (this.cornerstoneStyle.position) {
|
|
this.cornerstoneStyle = {}
|
|
this.setCanvasStyle()
|
|
} else {
|
|
this.cornerstoneStyle = {
|
|
position: 'absolute',
|
|
top: '72px',
|
|
left: '0px',
|
|
right: '350px',
|
|
zIndex: 10
|
|
}
|
|
this.canvasW = window.innerWidth - 570 + 'px'
|
|
this.canvasH = window.innerHeight - 130 + 'px'
|
|
}
|
|
this.$nextTick(() => {
|
|
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].reloadCanvas()
|
|
for (var i = 0; i < this.maxCanvas; i++) {
|
|
this.$refs[`dicomCanvas${i}`][0].reloadCanvas()
|
|
}
|
|
})
|
|
},
|
|
loadImageStacks(seriesList) {
|
|
if (seriesList.length === 0) {
|
|
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
|
|
if (idx > -1) {
|
|
store.dispatch('reading/setLastCanvasTaskId', this.visitTaskList[idx].VisitTaskId)
|
|
}
|
|
|
|
return
|
|
}
|
|
var l = seriesList.length > 1 ? 'A|B' : 'A'
|
|
this.layout = l
|
|
var i = this.layouts.findIndex(i => i.name === l)
|
|
var layout = this.layouts[i]
|
|
this.layoutRow = layout.row
|
|
this.layoutCol = layout.col
|
|
this.setCanvasStyle()
|
|
this.maxCanvas = layout.row * layout.col
|
|
this.$nextTick(() => {
|
|
const elements = document.querySelectorAll('.cornerstone-element')
|
|
Array.from(elements).forEach((element) => {
|
|
cornerstone.enable(element)
|
|
cornerstone.resize(element)
|
|
})
|
|
seriesList.map((series, index) => {
|
|
this.canvasObj[index] = series
|
|
if (series.isCurrentTask) {
|
|
this.currentDicomCanvasIndex = index
|
|
this.activeSeries = series
|
|
// this.$refs['measurementList'].initPage(series)
|
|
store.dispatch('reading/setActiveSeries', series)
|
|
store.dispatch('reading/setLastCanvasTaskId', series.visitTaskId)
|
|
}
|
|
this.$refs[`dicomCanvas${index}`][0].loadImageStack(series)
|
|
|
|
if (this.activeTool) {
|
|
if (series.isCurrentTask && series.readingTaskState < 2) {
|
|
this.$nextTick(() => {
|
|
this.$refs[`dicomCanvas${index}`][0].setToolPassive(this.activeTool)
|
|
})
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.$refs[`dicomCanvas${index}`][0].setToolEnabled(this.activeTool)
|
|
})
|
|
}
|
|
this.activeTool = ''
|
|
}
|
|
})
|
|
})
|
|
},
|
|
loadImageStack(dicomSeries) {
|
|
this.clipPlaying = false
|
|
this.fps = 15
|
|
this.canvasObj[this.currentDicomCanvasIndex] = dicomSeries
|
|
this.$nextTick(() => {
|
|
this.activeSeries = dicomSeries
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries).then(res => {
|
|
if (this.activeTool) {
|
|
if (dicomSeries.isCurrentTask && dicomSeries.readingTaskState < 2) {
|
|
this.$nextTick(() => {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(this.activeTool)
|
|
})
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
})
|
|
this.activeTool = ''
|
|
}
|
|
// this.activeTool = ''
|
|
}
|
|
})
|
|
// this.$refs['measurementList'].initPage(dicomSeries)
|
|
store.dispatch('reading/setActiveSeries', dicomSeries)
|
|
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
|
|
store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
|
|
}
|
|
})
|
|
},
|
|
loadLinkedImageStack(dicomSeries) {
|
|
this.currentDicomCanvasIndex = dicomSeries.canvasIndex
|
|
var canvasIndex = dicomSeries.canvasIndex
|
|
this.canvasObj[canvasIndex] = dicomSeries
|
|
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
if (this.activeTool) {
|
|
var series = null
|
|
if (canvasIndex === i) {
|
|
series = dicomSeries
|
|
} else {
|
|
series = this.$refs[`dicomCanvas${i}`][0].stack
|
|
}
|
|
if (series.isCurrentTask && series.readingTaskState < 2) {
|
|
this.$refs[`dicomCanvas${i}`][0].setToolPassive(this.activeTool)
|
|
} else {
|
|
this.$refs[`dicomCanvas${i}`][0].setToolEnabled(this.activeTool)
|
|
}
|
|
}
|
|
}
|
|
this.activeTool = ''
|
|
|
|
// if (this.activeTool) {
|
|
// if (dicomSeries.isCurrentTask && dicomSeries.readingTaskState < 2) {
|
|
// this.$nextTick(() => {
|
|
// this.$refs[`dicomCanvas${canvasIndex}`][0].setToolPassive(this.activeTool)
|
|
// })
|
|
// } else {
|
|
// this.$nextTick(() => {
|
|
// this.$refs[`dicomCanvas${canvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
// })
|
|
// }
|
|
// this.activeTool = ''
|
|
// }
|
|
this.$nextTick(() => {
|
|
this.activeSeries = dicomSeries
|
|
this.$refs[`dicomCanvas${canvasIndex}`][0].loadImageStack(dicomSeries)
|
|
|
|
store.dispatch('reading/setActiveSeries', dicomSeries)
|
|
if (this.currentDicomCanvasIndex === this.maxCanvas - 1) {
|
|
store.dispatch('reading/setLastCanvasTaskId', dicomSeries.visitTaskId)
|
|
}
|
|
})
|
|
},
|
|
// 给显示的画布设置显示的序列信息
|
|
async getSeriesShowInCanvas(layout) {
|
|
var activeSeries = Object.assign({}, this.activeSeries)
|
|
const loading = this.$loading({ fullscreen: true })
|
|
if (layout.name === 'A') {
|
|
// 判断当前激活窗口是否有序列信息
|
|
if (activeSeries) {
|
|
this.seriesStack = [activeSeries]
|
|
this.currentDicomCanvasIndex = 0
|
|
store.dispatch('reading/setLastCanvasTaskId', activeSeries.visitTaskId)
|
|
await this.setCanvas(this.seriesStack)
|
|
loading.close()
|
|
}
|
|
} else if (layout.name === 'A|A') {
|
|
if (activeSeries) {
|
|
this.seriesStack = [activeSeries, activeSeries]
|
|
this.currentDicomCanvasIndex = 1
|
|
store.dispatch('reading/setLastCanvasTaskId', activeSeries.visitTaskId)
|
|
await this.setCanvas(this.seriesStack)
|
|
loading.close()
|
|
}
|
|
} else if (layout.name === 'A|B') {
|
|
if (activeSeries) {
|
|
const idx = this.visitTaskList.findIndex(i => i.VisitTaskId === activeSeries.visitTaskId)
|
|
|
|
const visitTaskNum = idx > -1 ? this.visitTaskList[idx].VisitTaskNum : -1
|
|
if (visitTaskNum > 0 && this.visitTaskList.length > 1) {
|
|
var visitTaskId = ''
|
|
if (this.CriterionType === 10) {
|
|
const i = this.visitTaskList.findIndex(i => i.VisitTaskNum === visitTaskNum - 1)
|
|
visitTaskId = this.visitTaskList[i].VisitTaskId
|
|
} else {
|
|
const i = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
|
|
visitTaskId = this.visitTaskList[i].VisitTaskId
|
|
}
|
|
this.getFirstSeries(activeSeries, visitTaskId).then(async baseSerires => {
|
|
console.log(activeSeries)
|
|
this.seriesStack = [baseSerires, activeSeries]
|
|
this.currentDicomCanvasIndex = 1
|
|
store.dispatch('reading/setLastCanvasTaskId', activeSeries.visitTaskId)
|
|
await this.setCanvas(this.seriesStack)
|
|
loading.close()
|
|
})
|
|
} else {
|
|
this.seriesStack = [activeSeries, activeSeries]
|
|
this.currentDicomCanvasIndex = 1
|
|
store.dispatch('reading/setLastCanvasTaskId', activeSeries.visitTaskId)
|
|
await this.setCanvas(this.seriesStack)
|
|
loading.close()
|
|
}
|
|
}
|
|
} else if (layout.name === 'A|A|A|A') {
|
|
if (activeSeries) {
|
|
this.seriesStack = [activeSeries, activeSeries, activeSeries, activeSeries]
|
|
this.currentDicomCanvasIndex = 3
|
|
store.dispatch('reading/setLastCanvasTaskId', activeSeries.visitTaskId)
|
|
await this.setCanvas(this.seriesStack)
|
|
loading.close()
|
|
}
|
|
}
|
|
},
|
|
// 设置画布序列信息
|
|
setCanvas(seriesStack) {
|
|
return new Promise(resolve => {
|
|
var promiseArr = []
|
|
for (let i = 0; i < this.maxCanvas && i < seriesStack.length; i++) {
|
|
this.canvasObj[i] = seriesStack[i]
|
|
promiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(seriesStack[i]))
|
|
}
|
|
Promise.all(promiseArr).then(() => {
|
|
// this.activateDicomCanvas(this.currentDicomCanvasIndex)
|
|
resolve()
|
|
}).catch(() => { resolve() })
|
|
})
|
|
},
|
|
// 根据病灶标识定位图像
|
|
|
|
// 最后一个窗口显示当前访视下病灶所在的影像序列
|
|
// 其他窗口显示该病灶第一次出现的序列信息
|
|
imageLocation(obj) {
|
|
return new Promise(async resolve => {
|
|
var loading = null
|
|
var loadImagePromises = []
|
|
var isScrollSync = this.isScrollSync
|
|
if (this.isScrollSync) {
|
|
// 取消滚动同步
|
|
this.isScrollSync = false
|
|
}
|
|
|
|
var activeCanvasTaskId = obj.visitTaskId
|
|
|
|
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === activeCanvasTaskId)
|
|
if (index === -1) {
|
|
resolve()
|
|
return
|
|
}
|
|
|
|
var firstAddSeries = null
|
|
var currentAddSeries = null
|
|
if (this.isReadingTaskViewInOrder === 1) {
|
|
// 有序
|
|
// 获取病灶第一次出现的访视序列
|
|
var firstAddVisitTaskId = null
|
|
|
|
var idx = this.visitTaskList[index].MeasureData.findIndex(item => {
|
|
return item.OrderMarkName === obj.lesionName
|
|
})
|
|
if (idx > -1) {
|
|
firstAddVisitTaskId = this.visitTaskList[index].MeasureData[idx].FristAddTaskId
|
|
}
|
|
if (firstAddVisitTaskId) {
|
|
var taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === firstAddVisitTaskId)
|
|
if (taskIdx > -1 && !this.visitTaskList[taskIdx].IsInit) {
|
|
loading = this.$loading({ fullscreen: true })
|
|
if (!this.visitTaskList[taskIdx].measureDataInit) {
|
|
await store.dispatch('reading/getMeasuredData', this.visitTaskList[taskIdx].VisitTaskId)
|
|
}
|
|
if (!this.visitTaskList[taskIdx].studyListInit) {
|
|
await store.dispatch('reading/getStudyInfo', { trialId: this.trialId, subjectVisitId: this.visitTaskList[taskIdx].VisitId, visitTaskId: this.visitTaskList[taskIdx].VisitTaskId, taskBlindName: this.visitTaskList[taskIdx].TaskBlindName })
|
|
}
|
|
if (!this.visitTaskList[taskIdx].readingQuestionsInit) {
|
|
await store.dispatch('reading/getReadingQuestionAndAnswer', { trialId: this.trialId, visitTaskId: this.visitTaskList[taskIdx].VisitTaskId })
|
|
}
|
|
if (!this.visitTaskList[taskIdx].questionsInit) {
|
|
await store.dispatch('reading/getDicomReadingQuestionAnswer', { trialId: this.trialId, visitTaskId: this.visitTaskList[taskIdx].VisitTaskId })
|
|
}
|
|
|
|
await store.dispatch('reading/setStatus', { visitTaskId: this.visitTaskList[taskIdx].VisitTaskId })
|
|
}
|
|
if (this.CriterionType === 3 && obj.lesionType === 7 && obj.fromMark) {
|
|
const measureDataInfo = Object.assign({}, obj)
|
|
measureDataInfo.lesionName = obj.fromMark
|
|
firstAddSeries = this.getSeriesInfoByMark(firstAddVisitTaskId, measureDataInfo)
|
|
} else {
|
|
firstAddSeries = this.getSeriesInfoByMark(firstAddVisitTaskId, obj)
|
|
}
|
|
}
|
|
// 获取当前访视病灶所在的序列
|
|
currentAddSeries = this.getSeriesInfoByMark(activeCanvasTaskId, obj)
|
|
if (!firstAddSeries && currentAddSeries) {
|
|
// 存在首次出现的病灶及当前病灶
|
|
firstAddSeries = currentAddSeries
|
|
} else if (!firstAddSeries && !currentAddSeries) {
|
|
// 当前新病灶,且未画标记则显示当前的序列信息,不做处理
|
|
loading && loading.close()
|
|
this.isScrollSync = isScrollSync
|
|
this.setToolToTarget(obj)
|
|
resolve()
|
|
return
|
|
} else if (firstAddSeries && !currentAddSeries) {
|
|
// 当前访视序列与首次出现病灶的序列对齐
|
|
currentAddSeries = this.getLinkedSeries(firstAddSeries, activeCanvasTaskId)
|
|
|
|
if (!currentAddSeries) {
|
|
// 未找到对齐的,则就显示当前最后一个窗口现实的序列信息
|
|
currentAddSeries = this.$refs[`dicomCanvas${this.maxCanvas - 1}`][0].series
|
|
}
|
|
}
|
|
} else {
|
|
// 无序
|
|
currentAddSeries = this.getSeriesInfoByMark(activeCanvasTaskId, obj)
|
|
if (!currentAddSeries) {
|
|
// 未找到对齐的,则就显示当前最后一个窗口现实的序列信息
|
|
currentAddSeries = this.$refs[`dicomCanvas${this.maxCanvas - 1}`][0].series
|
|
}
|
|
firstAddSeries = currentAddSeries
|
|
}
|
|
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
if (i === this.maxCanvas - 1) {
|
|
loadImagePromises.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(currentAddSeries))
|
|
this.currentDicomCanvasIndex = i
|
|
this.activeSeries = currentAddSeries
|
|
store.dispatch('reading/setActiveSeries', currentAddSeries)
|
|
} else {
|
|
loadImagePromises.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(firstAddSeries))
|
|
}
|
|
}
|
|
Promise.all(loadImagePromises)
|
|
.then(() => {
|
|
this.isScrollSync = isScrollSync
|
|
this.setToolToTarget(obj)
|
|
resolve()
|
|
}).catch(() => {
|
|
resolve()
|
|
})
|
|
if (loading) {
|
|
loading.close()
|
|
}
|
|
})
|
|
},
|
|
setToolToTarget(obj) {
|
|
if (obj.readingTaskState < 2 && obj.markTool && !obj.isMarked) {
|
|
if (this.activeTool) {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
|
|
}
|
|
this.activeTool = obj.markTool
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(obj.markTool)
|
|
} else {
|
|
if (this.activeTool) {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
|
|
this.activeTool = ''
|
|
}
|
|
}
|
|
},
|
|
setToolPassive() {
|
|
if (this.activeTool) {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
|
|
this.activeTool = ''
|
|
}
|
|
},
|
|
selectViewCanvas(offset) {
|
|
var canvasIndex = this.currentDicomCanvasIndex + offset
|
|
if (canvasIndex < 0 || canvasIndex >= this.maxCanvas) return
|
|
this.activateDicomCanvas(canvasIndex)
|
|
},
|
|
// 根据标记获取标记所在的序列信息
|
|
getSeriesInfoByMark(visitTaskId, obj) {
|
|
var seriesInfo = null
|
|
// 根据任务ID测量病灶信息
|
|
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
|
|
|
|
if (index > -1) {
|
|
var idx = -1
|
|
idx = this.visitTaskList[index].MeasureData.findIndex(item => item.OrderMarkName === obj.lesionName)
|
|
// if (this.CriterionType === 10) {
|
|
// idx = this.visitTaskList[index].MeasureData.findIndex(item => item.OrderMarkName === obj.lesionName)
|
|
// } else {
|
|
// idx = this.visitTaskList[index].MeasureData.findIndex(item => item.QuestionId === obj.questionId && item.RowIndex === obj.rowIndex)
|
|
// }
|
|
if (idx > -1 && this.visitTaskList[index].MeasureData[idx].MeasureData) {
|
|
var studyList = this.visitTaskList[index].StudyList
|
|
var studyId = this.visitTaskList[index].MeasureData[idx].StudyId
|
|
var seriesId = this.visitTaskList[index].MeasureData[idx].SeriesId
|
|
var instanceId = this.visitTaskList[index].MeasureData[idx].InstanceId
|
|
var studyIdx = studyList.findIndex(study => study.StudyId === studyId)
|
|
if (studyIdx > -1) {
|
|
var seriesIdx = studyList[studyIdx].SeriesList.findIndex(s => s.seriesId === seriesId)
|
|
if (seriesIdx > -1) {
|
|
var series = studyList[studyIdx].SeriesList[seriesIdx]
|
|
const frame = this.visitTaskList[index].MeasureData[idx].MeasureData.frame
|
|
const filterStr = series.isExistMutiFrames ? `frame=${frame}&instanceId=${instanceId}` : `instanceId=${instanceId}`
|
|
var instanceIdx = series.imageIds.findIndex(imageId => imageId.includes(filterStr))
|
|
if (instanceIdx > -1) {
|
|
series.imageIdIndex = instanceIdx
|
|
seriesInfo = series
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return seriesInfo
|
|
},
|
|
getLinkedSeries(baseSeries, visitTaskId) {
|
|
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
|
|
var visitTaskInfo = this.visitTaskList[index]
|
|
var obj = null
|
|
var studyList = visitTaskInfo.StudyList
|
|
// 查找筛选描述一致
|
|
var seriesList = studyList.map(s => s.SeriesList).flat()
|
|
var similarArr = seriesList.map((i, index) => {
|
|
return { similar: this.strSimilarity2Percent(i.description, baseSeries.description), index }
|
|
})
|
|
similarArr = similarArr.sort((a, b) => {
|
|
return b.similar - a.similar
|
|
})
|
|
const i = similarArr[0] && similarArr[0].similar > 0.95 ? similarArr[0].index : -1
|
|
if (i > -1) {
|
|
obj = seriesList[i]
|
|
}
|
|
// if (!obj) {
|
|
// // 描述不一致,则筛选层厚一致
|
|
// const idx = seriesList.findIndex(series => series.sliceThickness === baseSeries.sliceThickness)
|
|
// idx > -1 ? obj = seriesList[idx] : ''
|
|
// }
|
|
// if (!obj) {
|
|
// // 层厚不一致,则筛选图像数量一致
|
|
// const idx = seriesList.findIndex(series => series.instanceCount === baseSeries.instanceCount)
|
|
// idx > -1 ? obj = seriesList[idx] : ''
|
|
// }
|
|
|
|
if (obj) {
|
|
const index = Math.floor(obj.imageIds.length * ((baseSeries.imageIdIndex + 1) / baseSeries.instanceCount))
|
|
obj.imageIdIndex = index > 0 ? index - 1 : 0
|
|
}
|
|
return obj
|
|
},
|
|
strSimilarity2Number(s, t) {
|
|
var n = s.length; var m = t.length; var d = []
|
|
var i, j, s_i, t_j, cost
|
|
if (n === 0) return m
|
|
if (m === 0) return n
|
|
for (i = 0; i <= n; i++) {
|
|
d[i] = []
|
|
d[i][0] = i
|
|
}
|
|
for (j = 0; j <= m; j++) {
|
|
d[0][j] = j
|
|
}
|
|
for (i = 1; i <= n; i++) {
|
|
s_i = s.charAt(i - 1)
|
|
for (j = 1; j <= m; j++) {
|
|
t_j = t.charAt(j - 1)
|
|
if (s_i === t_j) {
|
|
cost = 0
|
|
} else {
|
|
cost = 1
|
|
}
|
|
d[i][j] = this.Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost)
|
|
}
|
|
}
|
|
return d[n][m]
|
|
},
|
|
// 两个字符串的相似程度,并返回相似度百分比
|
|
strSimilarity2Percent(s, t) {
|
|
var l = s.length > t.length ? s.length : t.length
|
|
var d = this.strSimilarity2Number(s, t)
|
|
return Number((1 - d / l).toFixed(4))
|
|
},
|
|
Minimum(a, b, c) {
|
|
return a < b ? (a < c ? a : c) : (b < c ? b : c)
|
|
},
|
|
// 获取某个任务下可对齐的序列信息
|
|
async getFirstSeries(baseSeries, visitTaskId) {
|
|
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
|
|
if (!this.visitTaskList[index].studyListInit) {
|
|
await store.dispatch('reading/getStudyInfo', { trialId: this.trialId, subjectVisitId: this.visitTaskList[index].VisitId, visitTaskId: this.visitTaskList[index].VisitTaskId, taskBlindName: this.visitTaskList[index].TaskBlindName })
|
|
|
|
await store.dispatch('reading/getMeasuredData', this.visitTaskList[index].VisitTaskId)
|
|
}
|
|
var visitTaskInfo = this.visitTaskList[index]
|
|
var obj = null
|
|
var studyList = visitTaskInfo.StudyList
|
|
// 查找筛选描述一致
|
|
var seriesList = studyList.map(s => s.SeriesList).flat()
|
|
var similarArr = seriesList.map((i, index) => {
|
|
return { similar: this.strSimilarity2Percent(i.description, baseSeries.description), index }
|
|
})
|
|
similarArr = similarArr.sort((a, b) => {
|
|
return b.similar - a.similar
|
|
})
|
|
const i = similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
|
|
if (i > -1) {
|
|
obj = seriesList[i]
|
|
}
|
|
// if (!obj) {
|
|
// // 描述不一致,则筛选层厚一致
|
|
// const idx = seriesList.findIndex(series => series.sliceThickness === baseSeries.sliceThickness)
|
|
// idx > -1 ? obj = seriesList[idx] : ''
|
|
// }
|
|
// if (!obj) {
|
|
// // 层厚不一致,则筛选图像数量一致
|
|
// const idx = seriesList.findIndex(series => series.instanceCount === baseSeries.instanceCount)
|
|
// idx > -1 ? obj = seriesList[idx] : ''
|
|
// }
|
|
if (!obj) {
|
|
// 都不符合要求, 判断是否存在层厚为5的序列,否则显示第一个检查的第一个序列
|
|
const idx = seriesList.findIndex(series => series.isDicom && parseInt(series.instanceCount) === 5)
|
|
idx > -1 ? obj = seriesList[idx] : obj = seriesList[0]
|
|
}
|
|
|
|
if (obj) {
|
|
const index = Math.floor(obj.imageIds.length * ((baseSeries.imageIdIndex + 1) / baseSeries.instanceCount))
|
|
obj.imageIdIndex = index > 0 ? index - 1 : 0
|
|
}
|
|
return obj
|
|
},
|
|
async getFirstSeries2(visitTaskList) {
|
|
if (visitTaskList && !visitTaskList.studyListInit) {
|
|
await store.dispatch('reading/getStudyInfo', { trialId: this.trialId, subjectVisitId: visitTaskList.VisitId, visitTaskId: visitTaskList.VisitTaskId, taskBlindName: visitTaskList.TaskBlindName })
|
|
|
|
await store.dispatch('reading/getMeasuredData', visitTaskList.VisitTaskId)
|
|
}
|
|
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskList.VisitTaskId)
|
|
var studyList = this.visitTaskList[index].StudyList
|
|
var idx = studyList.findIndex(i => i.SeriesList.length > 0)
|
|
if (idx > -1) {
|
|
const seriesIdx = studyList[idx].SeriesList.findIndex(i => i.isDicom)
|
|
return seriesIdx > -1 ? studyList[idx].SeriesList[seriesIdx] : ''
|
|
} else {
|
|
return ''
|
|
}
|
|
},
|
|
|
|
// 设置画布大小
|
|
setCanvasStyle() {
|
|
this.canvasW = (window.innerWidth - 570) / this.layoutCol + 'px'
|
|
this.canvasH = (window.innerHeight - 130) / this.layoutRow + 'px'
|
|
},
|
|
// 切换布局
|
|
changeLayout(name) {
|
|
if (this.activeTool) {
|
|
if (this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isCurrentTask && this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState < 2) {
|
|
this.$nextTick(() => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
|
|
})
|
|
} else {
|
|
this.$nextTick(() => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
})
|
|
}
|
|
this.activeTool = ''
|
|
}
|
|
this.isScrollSync = false
|
|
this.activeSeries = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack
|
|
this.layout = name
|
|
var i = this.layouts.findIndex(i => i.name === name)
|
|
var layout = this.layouts[i]
|
|
this.layoutRow = layout.row
|
|
this.layoutCol = layout.col
|
|
this.setCanvasStyle()
|
|
this.maxCanvas = layout.row * layout.col
|
|
this.$nextTick(() => {
|
|
const elements = document.querySelectorAll('.cornerstone-element')
|
|
Array.from(elements).forEach((element) => {
|
|
cornerstone.enable(element)
|
|
cornerstone.resize(element)
|
|
})
|
|
this.getSeriesShowInCanvas(layout)
|
|
this.cornerstoneStyle = {}
|
|
this.setCanvasStyle()
|
|
})
|
|
},
|
|
// 更新画布
|
|
updateCanvas(measureData) {
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
var stack = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack
|
|
if (stack.studyId) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].removeToolState(measureData)
|
|
}
|
|
}
|
|
},
|
|
// 旋转
|
|
setDicomCanvasRotate(value) {
|
|
const type = parseInt(value)
|
|
if (type === 1) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetRotate()
|
|
} else if (type === 2) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, true, 0, type)
|
|
} else if (type === 3) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(true, false, 0, type)
|
|
} else if (type === 4) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, -90, type)
|
|
} else if (type === 5) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, 90, type)
|
|
}
|
|
},
|
|
// 激活画布
|
|
activateDicomCanvas(index) {
|
|
console.log('激活画布')
|
|
|
|
if (index !== this.currentDicomCanvasIndex) {
|
|
this.currentDicomCanvasIndex = index
|
|
// var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
|
|
var dicomSeries = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack
|
|
this.activeSeries = dicomSeries
|
|
for (let i = 0; i < this.maxCanvas; i++) {
|
|
if (this.activeTool) {
|
|
var series = this.$refs[`dicomCanvas${i}`][0].stack
|
|
if (series.isCurrentTask && series.readingTaskState < 2) {
|
|
this.$refs[`dicomCanvas${i}`][0].setToolPassive(this.activeTool)
|
|
} else {
|
|
this.$refs[`dicomCanvas${i}`][0].setToolEnabled(this.activeTool)
|
|
}
|
|
}
|
|
}
|
|
this.activeTool = ''
|
|
this.isScrollSync = false
|
|
this.currentDicomCanvasIndex = index
|
|
this.currentDicomCanvas = this.$refs[`dicomCanvas${index}`]
|
|
this.currentDicomCanvas.tabIndex = 0
|
|
if (!this.rotateList[this.currentDicomCanvasIndex]) {
|
|
this.rotateList[this.currentDicomCanvasIndex] = '1'
|
|
}
|
|
if (!this.colorList[this.currentDicomCanvasIndex]) {
|
|
this.colorList[this.currentDicomCanvasIndex] = ''
|
|
}
|
|
if (!this.wwwcList[this.currentDicomCanvasIndex]) {
|
|
this.wwwcList[this.currentDicomCanvasIndex] = '1'
|
|
}
|
|
this.$refs['container'].focus()
|
|
// if (stack.studyId) {
|
|
// DicomEvent.$emit('toggleVisitList', stack)
|
|
// }
|
|
store.dispatch('reading/setActiveSeries', dicomSeries)
|
|
}
|
|
},
|
|
// 鼠标移入测量工具时,判断工具是否可激活
|
|
enter(e, toolName) {
|
|
var i = this.measuredTools.findIndex(item => item.toolName === toolName)
|
|
if (i === -1) return
|
|
var isCurrentTask = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isCurrentTask
|
|
var readingTaskState = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].readingTaskState
|
|
if (!isCurrentTask || readingTaskState >= 2) {
|
|
this.measuredTools[i].isDisabled = true
|
|
e.target.style.cursor = 'not-allowed'
|
|
if (this.activeTool) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(toolName)
|
|
this.activeTool = ''
|
|
}
|
|
} else {
|
|
// var obj = this.$refs['measurementList'].isCanActiveTool(toolName, true)
|
|
var obj = this.$refs['measurementList'].isCanActiveTool(toolName, true)
|
|
this.measuredTools[i].disabledReason = obj.reason
|
|
if (!obj.isCanActiveTool) {
|
|
if (this.activeTool === toolName) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
|
|
this.activeTool = ''
|
|
}
|
|
this.measuredTools[i].isDisabled = true
|
|
e.target.style.cursor = 'not-allowed'
|
|
} else {
|
|
this.measuredTools[i].isDisabled = false
|
|
e.target.style.cursor = 'pointer'
|
|
}
|
|
}
|
|
},
|
|
setMeasuredToolsPassive() {
|
|
this.measuredTools.forEach(item => {
|
|
if (this.activeTool === item.toolName) {
|
|
this.activeTool = ''
|
|
}
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
},
|
|
// 设置测量工具启用(不会对输入作出反应)
|
|
setToolActive(toolName, isMeasuredTool, e, type) {
|
|
if (isMeasuredTool) {
|
|
// var i = this.measuredTools.findIndex(item => item.toolName === toolName)
|
|
// if (i === -1 && this.measuredTools[i].isDisabled) return
|
|
|
|
var toolObj = this.measuredTools.find(i => i.toolName === toolName)
|
|
if (!toolObj || toolObj.isDisabled) return
|
|
var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
|
|
if (dicomSeries.isCurrentTask && isMeasuredTool && dicomSeries.readingTaskState < 2) {
|
|
if (this.activeTool) {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
if (this.activeTool === toolName) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
|
|
this.activeTool = ''
|
|
} else {
|
|
this.activeTool = toolName
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
|
|
}
|
|
} else {
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
|
|
})
|
|
this.activeTool = toolName
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
|
|
}
|
|
} else {
|
|
if (!this.activeTool) return
|
|
this.measuredTools.forEach(item => {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(item.toolName)
|
|
})
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(toolName)
|
|
this.activeTool = ''
|
|
}
|
|
} else {
|
|
if (this.activeTool === toolName) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(toolName)
|
|
this.activeTool = ''
|
|
} else {
|
|
this.activeTool = toolName
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
|
|
}
|
|
}
|
|
},
|
|
// 设置测量工具禁用(不会对输入作出反应)
|
|
setToolEnabled() {
|
|
var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
|
|
if (!dicomSeries.isCurrentTask) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
this.activeTool = ''
|
|
return
|
|
}
|
|
if (this.activeTool) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
|
|
this.activeTool = ''
|
|
}
|
|
},
|
|
// 影像适应图像/适应窗口
|
|
fitToType(toolName) {
|
|
if (this.activeTool !== 'fitToWindow' && this.activeTool !== 'fitToImage') {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
|
|
}
|
|
if (toolName === 'fitToWindow') {
|
|
this.fitType = 0
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToWindow()
|
|
} else if (toolName === 'fitToImage') {
|
|
this.fitType = 1
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].fitToImage()
|
|
}
|
|
this.activeTool = toolName
|
|
},
|
|
// 切换帧
|
|
scrollPage(i) {
|
|
// 获取影像是否下载完成
|
|
const isLoaded = this.getSeriesLoadStatus()
|
|
if (!isLoaded) return
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].scrollPage(i)
|
|
},
|
|
// 播放/暂停
|
|
toggleClipPlay(isPlay) {
|
|
// 获取影像是否下载完成
|
|
const isLoaded = this.getSeriesLoadStatus()
|
|
if (!isLoaded) return
|
|
this.clipPlaying = isPlay
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(this.fps)
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleClipPlay(isPlay)
|
|
},
|
|
getSeriesLoadStatus() {
|
|
const index = this.visitTaskList.findIndex(i => i.VisitTaskId === this.activeSeries.visitTaskId)
|
|
if (index === -1) return false
|
|
const loadStatus = this.visitTaskList[index].StudyList[this.activeSeries.studyIndex].SeriesList[this.activeSeries.seriesIndex].loadStatus
|
|
return loadStatus
|
|
},
|
|
setDicomCanvasfps(event) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setFps(event.target.value)
|
|
},
|
|
// 添加标记
|
|
setMeasureData(data) {
|
|
this.$refs['measurementList'].setMeasuredData(data)
|
|
this.activeTool = ''
|
|
},
|
|
// 修改标记
|
|
modifyMeasureData(data) {
|
|
this.$refs['measurementList'].modifyMeasuredData(data)
|
|
this.activeTool = ''
|
|
},
|
|
async saveImage() {
|
|
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].saveImage()
|
|
// canvas为转换后的Canvas对象
|
|
const divForDownloadViewport = document.querySelector(
|
|
`div[data-canvas-uid="dicomCanvas${this.currentDicomCanvasIndex}"]`
|
|
)
|
|
var canvas = await html2canvas(divForDownloadViewport)
|
|
let oImg = new Image()
|
|
oImg = canvas.toDataURL('image/png', 1)// 导出图片
|
|
var oA = document.createElement('a')
|
|
var subjectCode = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].subjectCode
|
|
var taskBlindName = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack.taskBlindName
|
|
var timestamp = Date.now()
|
|
oA.download = `${subjectCode}_${taskBlindName}_${timestamp}`// 设置下载的文件名,默认是'下载'
|
|
oA.href = oImg
|
|
document.body.appendChild(oA)
|
|
oA.click()
|
|
oA.remove() // 下载之后把创建的元素删除
|
|
},
|
|
// 设置窗宽/窗位
|
|
setDicomCanvasWwwc(v) {
|
|
if (v.val === -1) {
|
|
// 默认值
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
|
|
} else if (v.val === 0) {
|
|
// 自定义
|
|
this.setCustomWwwc()
|
|
} else if (v.val === 1) {
|
|
// 区域窗宽
|
|
// this.setToolActive('WwwcRegion', false)
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive('WwwcRegion')
|
|
} else if (v.val === 8) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
|
|
} else {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setWwwc(v.ww, v.wc)
|
|
}
|
|
},
|
|
setCustomWwwc() {
|
|
var wwwc = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].dicomInfo.wwwc
|
|
this.activeCanvasWW = wwwc ? parseInt(wwwc.split('/')[0]) : null
|
|
this.activeCanvasWC = wwwc ? parseInt(wwwc.split('/')[1]) : null
|
|
this.customWwc.visible = true
|
|
},
|
|
setWwwc(v) {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setWwwc(v.ww, v.wc)
|
|
this.customWwc.visible = false
|
|
},
|
|
toggleInvert() {
|
|
if (this.activeTool === 'reversecolor') {
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
|
|
this.activeTool = ''
|
|
} else {
|
|
this.activeTool = 'reversecolor'
|
|
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
|
|
}
|
|
},
|
|
setImageIndexSync() {
|
|
this.isScrollSync = !this.isScrollSync
|
|
},
|
|
scrollSync(obj) {
|
|
for (var i = 0; i < this.maxCanvas; i++) {
|
|
if (i !== this.currentDicomCanvasIndex) {
|
|
this.$refs[`dicomCanvas${i}`][0].scrollPage(obj.offset)
|
|
}
|
|
}
|
|
},
|
|
showPanel(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'block'
|
|
},
|
|
handleMouseout(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'none'
|
|
},
|
|
// 预览临床数据
|
|
previewCD() {
|
|
this.$emit('previewCD')
|
|
},
|
|
previewNoneDicoms() {
|
|
this.$emit('previewNoneDicoms')
|
|
},
|
|
previewManuals() {
|
|
this.isFullscreen = false
|
|
this.manualsDialog.visible = true
|
|
},
|
|
handleFusion() {
|
|
// https 或者 本地开发环境才是安全上下文
|
|
if (!window.isSecureContext) {
|
|
this.$alert(this.$t('components:uploadvideo:message:xf3'))
|
|
return
|
|
}
|
|
// 顶部文档是否开启跨源隔离
|
|
if (!window.crossOriginIsolated) {
|
|
this.$alert(this.$t('components:uploadvideo:message:xf4'))
|
|
return
|
|
}
|
|
if (this.imageQualityIssues && parseInt(this.imageQualityIssues) === 6) {
|
|
this.$alert(this.$t('trials:lugano:message:fusionWarn'))
|
|
return
|
|
}
|
|
const i = this.activeTaskInfo.visitTaskIndex
|
|
if (i < 0) return
|
|
if (this.studyList.length > 0) {
|
|
this.fusionForm.studyID = this.studyList[0].StudyId
|
|
this.handleStudyIdChange(this.studyList[0].StudyId)
|
|
} else {
|
|
this.fusionForm.studyID = ''
|
|
this.ctSeries = []
|
|
this.petSeries = []
|
|
}
|
|
|
|
this.fusionForm.visitTaskId = this.visitTaskList[i].VisitTaskId
|
|
this.fusionForm.readingTaskState = this.visitTaskList[i].ReadingTaskState
|
|
this.fusionForm.taskBlindName = this.visitTaskList[i].TaskBlindName
|
|
this.fusionForm.subjectCode = this.visitTaskList[i].SubjectCode
|
|
this.fusionForm.isBaseLineTask = this.visitTaskList[i].IsBaseLineTask
|
|
this.fusionForm.isCurrentTask = this.visitTaskList[i].IsCurrentTask
|
|
this.fusionSeries.visible = true
|
|
},
|
|
handleStudyIdChange(v) {
|
|
var i = this.studyList.findIndex(i => i.StudyId === v)
|
|
if (i === -1) {
|
|
this.ctSeries = []
|
|
this.petSeries = []
|
|
} else {
|
|
var seriesList = this.studyList[i].SeriesList
|
|
var series = seriesList.filter(series => series.modality === 'CT')
|
|
this.ctSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
|
|
|
|
series = seriesList.filter(series => series.modality === 'PT')
|
|
this.petSeries = series.sort((a, b) => b.instanceCount - a.instanceCount)
|
|
}
|
|
},
|
|
handleCTSelectionChange(rows) {
|
|
if (rows.length > 0) {
|
|
this.ctSeriesInfo = rows[0]
|
|
} else {
|
|
this.ctSeriesInfo = {}
|
|
}
|
|
},
|
|
handleCTSelect(selection) {
|
|
if (selection.length > 1) {
|
|
const del_row = selection.shift()
|
|
this.$refs.ctSeries.toggleRowSelection(del_row, false)
|
|
}
|
|
},
|
|
handlePTSelect(selection) {
|
|
if (selection.length > 1) {
|
|
const del_row = selection.shift()
|
|
this.$refs.petSeries.toggleRowSelection(del_row, false)
|
|
}
|
|
},
|
|
handlePTSelectionChange(rows) {
|
|
if (rows.length > 0) {
|
|
this.petSeriesInfo = rows[0]
|
|
} else {
|
|
this.petSeriesInfo = {}
|
|
}
|
|
},
|
|
handleSubmitFusionSeries() {
|
|
this.$refs['fusionForm'].validate((valid) => {
|
|
if (!valid) return
|
|
if (Object.keys(this.ctSeriesInfo).length === 0 || Object.keys(this.petSeriesInfo).length === 0) {
|
|
// '请选择序列信息!'
|
|
this.$confirm(this.$t('trials:lugano:fusionDialog:message:checkSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
|
|
showCancelButton: false,
|
|
type: 'warning'
|
|
}).then(() => {}).catch(() => {})
|
|
return
|
|
}
|
|
var count = Math.abs(this.ctSeriesInfo.instanceCount - this.petSeriesInfo.instanceCount)
|
|
if (count > 10) {
|
|
// '选择的两组序列,影像数存在较大差距, 是否继续?'
|
|
this.$confirm(this.$t('trials:lugano:fusionDialog:message:validSeries'), this.$t('trials:lugano:fusionDialog:warning'), {
|
|
type: 'warning'
|
|
}).then(() => {
|
|
this.fusion()
|
|
}).catch(() => {})
|
|
} else {
|
|
this.fusion()
|
|
}
|
|
})
|
|
},
|
|
fusion() {
|
|
// sessionStorage.setItem('ctSeriesInfo', JSON.stringify(this.ctSeriesInfo))
|
|
// sessionStorage.setItem('petSeriesInfo', JSON.stringify(this.petSeriesInfo))
|
|
this.fusionSeries.visible = false
|
|
var token = getToken()
|
|
var trialReadingCriterionId = this.$router.currentRoute.query.TrialReadingCriterionId
|
|
var trialId = this.$router.currentRoute.query.trialId
|
|
var digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
|
var path = `/petct?TrialReadingCriterionId=${trialReadingCriterionId}&trialId=${trialId}&visitTaskId=${this.fusionForm.visitTaskId}&taskBlindName=${this.fusionForm.taskBlindName}&subjectCode=${this.fusionForm.subjectCode}&readingTaskState=${this.fusionForm.readingTaskState}&isBaseLineTask=${this.fusionForm.isBaseLineTask}&isCurrentTask=${this.fusionForm.isCurrentTask}&isReadingShowSubjectInfo=${this.isReadingShowSubjectInfo}&studyId=${this.fusionForm.studyID}&ctseriesId=${this.ctSeriesInfo.seriesId}&ptseriesId=${this.petSeriesInfo.seriesId}&digitPlaces=${digitPlaces}&TokenKey=${token}&lang=${this.$i18n.locale}`
|
|
var routeData = this.$router.resolve({ path })
|
|
if (this.petctWindow) {
|
|
this.petctWindow.close()
|
|
}
|
|
this.petctWindow = window.open(routeData.href, '_blank')
|
|
this.$nextTick(() => { this.petct.visible = true })
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.dicom-viewer-wrapper{
|
|
height: 100%;
|
|
padding: 5px 0px 5px 5px;
|
|
box-sizing: border-box;
|
|
.divider{
|
|
display: block;
|
|
height: 1px;
|
|
width: 100%;
|
|
margin: 10px 0;
|
|
// background-color: #383838;
|
|
// color: #fff;
|
|
// background-color: #DCDFE6;
|
|
}
|
|
.el-divider__text{
|
|
padding: 0 10px;
|
|
color: #fff;
|
|
background-color: #383838;
|
|
font-size: 12px;
|
|
width: 80px;
|
|
}
|
|
.dicom-viewer-container{
|
|
display:flex;
|
|
flex-direction: column;
|
|
height: 100%;
|
|
}
|
|
::-webkit-scrollbar {
|
|
width: 5px;
|
|
height: 5px;
|
|
}
|
|
::-webkit-scrollbar-thumb {
|
|
border-radius: 10px;
|
|
background: #d0d0d0;
|
|
}
|
|
.dicom-tools{
|
|
box-sizing: border-box;
|
|
width: 100%;
|
|
height: 80px;
|
|
padding: 0 5px;
|
|
border: 1px solid #727272;
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
.tool-wrapper{
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
align-items: center;
|
|
margin-right: 20px;
|
|
.icon{
|
|
padding: 5px;
|
|
border: 1px solid #404040;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
.svg-icon{
|
|
font-size:20px;
|
|
color:#ddd;
|
|
}
|
|
}
|
|
.text{
|
|
position: relative;
|
|
font-size: 12px;
|
|
margin-top: 5px;
|
|
color: #d0d0d0;
|
|
display: none;
|
|
}
|
|
}
|
|
.tool-frame{
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
margin-right: 20px;
|
|
border: 1px solid #404040;
|
|
.icon{
|
|
padding: 5px;
|
|
border-right: 1px solid #404040;
|
|
cursor: pointer;
|
|
text-align: center;
|
|
.svg-icon{
|
|
font-size:20px;
|
|
color:#ddd;
|
|
}
|
|
}
|
|
.select-wrapper{
|
|
width: 60px;
|
|
background-color: black;
|
|
color: #ddd;
|
|
border: none;
|
|
font-size: 13px;
|
|
outline: none;
|
|
}
|
|
.text{
|
|
position: relative;
|
|
font-size: 12px;
|
|
margin-top: 5px;
|
|
color: #d0d0d0;
|
|
display: none;
|
|
}
|
|
}
|
|
.tool_active{
|
|
background-color: #607d8b;
|
|
}
|
|
.tool_disabled{
|
|
cursor:not-allowed
|
|
}
|
|
.icon:hover{
|
|
background-color: #607d8b;
|
|
}
|
|
.dropdown {
|
|
position: relative;
|
|
display: inline-block;
|
|
.text{
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
.dropdown-content {
|
|
display: none;
|
|
position: absolute;
|
|
background-color: #383838;
|
|
color: #fff;
|
|
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
|
|
z-index: 9999;
|
|
font-size: 12px;
|
|
ul{
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
text-align: center;
|
|
li{
|
|
a{
|
|
display: block;
|
|
padding: 5px;
|
|
}
|
|
}
|
|
}
|
|
ul li:hover{
|
|
background-color: #727272;
|
|
}
|
|
}
|
|
|
|
// .dropdown:hover .dropdown-content {
|
|
// display: block;
|
|
|
|
// }
|
|
.layout-content ul li{
|
|
border-top:1px solid #ddd;
|
|
border-left:1px solid #ddd;
|
|
}
|
|
.layout-content ul .flex_row{
|
|
// border: 1px solid #ddd;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
// padding: 2px;
|
|
margin-bottom: 2px;
|
|
}
|
|
.layout-content ul .flex_column{
|
|
display: flex;
|
|
justify-content: space-between;
|
|
flex-direction: column;
|
|
align-items: center;
|
|
margin-bottom: 2px;
|
|
}
|
|
.layout_box_1_1{
|
|
flex:1;
|
|
// border: 1px solid #ddd;
|
|
line-height: 30px;
|
|
font-size: 12px;
|
|
text-align: center;
|
|
border-bottom:1px solid #ddd;
|
|
border-right:1px solid #ddd;
|
|
// padding: 0 5px;
|
|
}
|
|
.layout_box_1_2{
|
|
flex:1;
|
|
// border: 1px solid #ddd;
|
|
line-height: 15px;
|
|
font-size: 10px;
|
|
text-align: center;
|
|
border-bottom:1px solid #ddd;
|
|
border-right:1px solid #ddd;
|
|
// padding: 0 5px;
|
|
}
|
|
.layout-content li .layout_box_1_1 :last-child{
|
|
color: red;
|
|
}
|
|
// .layout_li:last-child{
|
|
// .layout_box{
|
|
// border-bottom: none;
|
|
// }
|
|
// }
|
|
.layout-content li:hover {
|
|
cursor: pointer;
|
|
background-color: #727272;
|
|
}
|
|
|
|
}
|
|
.dicom-viewers{
|
|
box-sizing: border-box;
|
|
flex: 1;
|
|
// width: 100%;
|
|
margin-top: 5px;
|
|
height: 100%;
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
.form-container{
|
|
// box-sizing: border-box;
|
|
width: 350px;
|
|
height: 100%;
|
|
border: 1px solid #727272;
|
|
// overflow-y: auto;
|
|
}
|
|
.viewer-container{
|
|
box-sizing: border-box;
|
|
flex: 1;
|
|
height: 100%;
|
|
border: 1px solid #727272;
|
|
}
|
|
|
|
.measurement-container{
|
|
// height: 100%;
|
|
overflow-y: auto;
|
|
}
|
|
.box{
|
|
display: grid;
|
|
box-sizing: border-box;
|
|
height: 100%;
|
|
padding: 0;
|
|
.item{
|
|
box-sizing: border-box;
|
|
position: relative;
|
|
border: 1px solid rgba(255, 255, 255, 0.21);
|
|
position: relative;
|
|
&_active{
|
|
// border: 2px solid #ffeb3b;fff;#428bca
|
|
// border: 1.5px dashed #ffeb3b;
|
|
border: 1px dashed rgb(250, 250, 0);
|
|
|
|
}
|
|
}
|
|
}
|
|
.box_1_1{
|
|
grid-template-columns: repeat(1, 100%); //1列,占100%
|
|
grid-template-rows: repeat(1, 100%); //1行,占100%
|
|
}
|
|
.box_1_2{
|
|
grid-template-columns: repeat(2, 50%); //1列,占50%
|
|
grid-template-rows: repeat(1, 100%); //1行,占100%
|
|
}
|
|
.box_2_1{
|
|
grid-template-columns: repeat(1, 100%); //1列,占100%
|
|
grid-template-rows: repeat(2, 50%); //1行,占50%
|
|
}
|
|
.box_2_2{
|
|
grid-template-columns: repeat(2, 50%); //1列,占50%
|
|
grid-template-rows: repeat(2, 50%); //1行,占50%
|
|
}
|
|
|
|
// .box_3_1{
|
|
// grid-template-columns: repeat(3, 100%); //1列,占100%
|
|
// grid-template-rows: repeat(3, 33.33%); //1行,占100%
|
|
// }
|
|
// .box_3_2{
|
|
// grid-template-columns: repeat(3, 50%); //1列,占100%
|
|
// grid-template-rows: repeat(3, 50%); //1行,占100%
|
|
// }
|
|
// .box_3_3{
|
|
// grid-template-columns: repeat(3, 33.33%); //1列,占100%
|
|
// grid-template-rows: repeat(3, 33.33%); //1行,占100%
|
|
// }
|
|
|
|
}
|
|
.personal_config {
|
|
/deep/ .el-tabs__content{
|
|
height: 450px;
|
|
overflow-y: auto;
|
|
}
|
|
}
|
|
/deep/ .manuals-dialog-container{
|
|
margin-top: 50px !important;
|
|
width:75%;
|
|
height:80%;
|
|
.el-dialog__body{
|
|
padding: 10px;
|
|
height: calc(100% - 50px) !important;
|
|
}
|
|
.el-dialog__header{
|
|
position: relative;
|
|
}
|
|
}
|
|
/deep/ .manuals-full-dialog-container{
|
|
.el-dialog__body{
|
|
padding: 10px;
|
|
height: calc(100% - 50px) !important;
|
|
}
|
|
.el-dialog__header{
|
|
position: relative;
|
|
}
|
|
}
|
|
.petct_wrapper{
|
|
position: absolute;
|
|
left: -205px;
|
|
right: 345px;
|
|
height: 100%;
|
|
background-color: #000000;
|
|
}
|
|
.series-table{
|
|
/deep/.el-table{
|
|
background-color: #1e1e1e !important;
|
|
color: #dfdfdf;
|
|
}
|
|
/deep/.el-table td.el-table__cell, .el-table th.el-table__cell.is-leaf{
|
|
border-bottom: 1px solid #dfdfdf;
|
|
}
|
|
.el-table--border::after, .el-table--group::after, .el-table::before{
|
|
background-color: #1e1e1e;
|
|
}
|
|
/deep/.el-table__header-wrapper{
|
|
th{
|
|
background-color: #1e1e1e !important;
|
|
color: #dfdfdf;
|
|
}
|
|
}
|
|
/deep/.el-table__body-wrapper{
|
|
tr{
|
|
background-color: #1e1e1e !important;
|
|
color: #dfdfdf;
|
|
}
|
|
tr:hover > td{
|
|
background-color: #1e1e1e !important;
|
|
}
|
|
}
|
|
/deep/.el-table__empty-block{
|
|
background-color: #1e1e1e !important;
|
|
}
|
|
}
|
|
}
|
|
|
|
</style>
|