irc_web/.svn/pristine/07/07e70a66ef0d4fb21c6983d4027...

1878 lines
74 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="dicom-viewer-wrapper">
<div class="dicom-viewer-container">
<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" 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;padding: 0 10px;">
<li v-for="item in wwwcArr" :key="item.label">
<a href="#" @click.prevent="setDicomCanvasWwwc(item)">
<div v-if="item.wc" 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;padding:0 10px;">
<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>
<div style="margin-left:auto;">
<div style="padding:5px">
<!-- 临床数据 -->
<el-button v-if="isExistsClinicalData" type="text" @click="previewCD">{{ $t('trials:reading:button:clinicalData') }}</el-button>
<!-- <el-button v-if="isExistsNoDicomFile" type="text" @click="previewNoneDicoms">非Dicom文件</el-button> -->
<el-button type="text" @click="previewHotkeys">{{ $t('trials:hotkeys:title:hotkey') }}</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 : {}"
@dblclick="setCornerstoneStyle(i-1)"
@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"
:hot-key-list="hotKeyList"
@setMeasureData="setMeasureData"
@modifyMeasureData="modifyMeasureData"
@scrollSync="scrollSync"
@selectViewCanvas="selectViewCanvas"
/>
</div>
</div>
<div ref="form-container" class="form-container">
<!-- 激活canvas测量数据 -->
<MeasurementList
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"
/>
<RecistBMQuestionList
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>
<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 @close="customWwc.visible = false" @setWwwc="setWwwc" />
</el-dialog>
<el-dialog
v-if="hotkeysDialog.visible"
:visible.sync="hotkeysDialog.visible"
:close-on-click-modal="false"
:title="hotkeysDialog.title"
width="600px"
>
<Hotkeys :reading-tool="0" @reset="resetHotkeyList" @close="hotkeysDialog.visible = false" />
<!-- <el-descriptions class="margin-top" :column="2" size="mini" border>
<el-descriptions-item v-for="item in hotKeyList" :key="item.id">
<template slot="label">
{{ $fd('ShortcutKey',item.shortcutKeyEnum) }}
</template>
{{ item.text }}
</el-descriptions-item>
</el-descriptions> -->
</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 DicomCanvas from './DicomCanvas'
import DicomCanvas from '@/views/trials/trials-panel/reading/dicoms/components/DicomCanvas.vue'
import MeasurementList from './MeasurementList'
import RecistBMQuestionList from './RecistBM/QuestionList'
import CustomWwwcForm from './CustomWwwcForm'
import Hotkeys from './Hotkeys'
import DicomEvent from './DicomEvent'
import { mapGetters } from 'vuex'
import store from '@/store'
import { getDoctorShortcutKey } from '@/api/user'
export default {
name: 'DicomViewer',
components: { DicomCanvas, MeasurementList, CustomWwwcForm, Hotkeys, RecistBMQuestionList },
props: {
isShow: {
type: Boolean,
required: true
},
isExistsClinicalData: {
type: Boolean,
default: false
},
isExistsNoDicomFile: {
type: Boolean,
default: false
},
isReadingShowSubjectInfo: {
type: Boolean,
required: true
},
isReadingTaskViewInOrder: {
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: [
{ 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', val: 5, wc: 40, ww: 80 },
{ label: 'CT Neck', val: 5, wc: 700, ww: 4000 },
{ label: 'CT Heart', val: 5, wc: 300, ww: 600 },
{ label: 'CT Lungs', val: 7, wc: -400, ww: 1500 },
{ label: 'CT Chest', val: 6, wc: 40, ww: 400 },
{ label: 'CT Abdomen', val: 2, wc: 60, ww: 400 },
{ label: 'CT Liver', val: 2, wc: 40, ww: 400 },
{ label: 'CT Bone', val: 4, wc: 300, ww: 1500 }
// { label: 'CT Angio', val: 3, wc: 300, ww: 600 },
],
activeSeries: {},
seriesStack: [],
trialId: '',
isScrollSync: false,
imageIndexSync: {
sourceCanvas: '',
targetCanvas: []
},
isFirstRender: false,
customWwc: { visible: false, title: null }, // 自定义调窗
hotkeysDialog: { visible: false, title: this.$t('trials:hotkeys:title:hotkey') }, // 热键
layout: '',
isFirstNotLinked: false,
hotKeyList: []
}
},
computed: {
...mapGetters(['visitTaskList'])
},
mounted() {
this.getHotKeys()
// cornerstone.imageCache.setMaximumSizeBytes(0)
const maximumSizeInBytes = 1024 * 1024 * 1024 // 1 GB
// const maximumSizeInBytes = 1024 * 1024 * 500
cornerstone.imageCache.setMaximumSizeBytes(maximumSizeInBytes)
// const cacheInfo = cornerstone.imageCache.getCacheInfo()
// console.log(cacheInfo)
this.customWwc = { visible: false, title: this.$t('trials:reading:dagTitle:wwwcCustom') }
// this.isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder === 'true'
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
console.log(this.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
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()
// if (callback) {
// callback(res)
// }
}
}
console.log('getMeasureData')
})
DicomEvent.$on('getScreenshots', (callback) => {
var base64Str = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].getScreenshots()
callback(base64Str)
console.log('getScreenshots')
})
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')
})
},
beforeDestroy() {
DicomEvent.$off('updateImage')
DicomEvent.$off('getMeasureData')
DicomEvent.$off('imageLocation')
DicomEvent.$off('setReadingState')
DicomEvent.$off('loadImageStacks')
DicomEvent.$off('loadLinkedImageStack')
},
methods: {
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(false, true, 0, 3)
} else if (shortcutKeyEnum === 10) {
// 垂直翻转
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(true, false, 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(this.wwwcArr[wwwcArrIdx].ww, this.wwwcArr[wwwcArrIdx].wc)
} else if (shortcutKeyEnum === 18) {
// 重置
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetViewport()
}
})
},
previewHotkeys() {
this.hotkeysDialog.visible = true
},
setCornerstoneStyle(i) {
if (this.cornerstoneStyle.position) {
this.cornerstoneStyle = {}
this.setCanvasStyle()
} else {
this.cornerstoneStyle = {
position: 'absolute',
top: '72px',
left: '205px',
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) {
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)
}
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.canvasObj[this.currentDicomCanvasIndex] = dicomSeries
if (this.activeTool) {
if (dicomSeries.isCurrentTask && dicomSeries.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.$nextTick(() => {
this.activeSeries = dicomSeries
// !this.isFirstRender || dicomSeries.isFirstRender
// if (!this.isFirstRender) {
// this.isFirstRender = true
// const idx = this.visitTaskList.findIndex(i => i.VisitTaskId === dicomSeries.visitTaskId)
// if (!this.visitTaskList[idx].IsBaseLineTask && this.isReadingTaskViewInOrder && this.visitTaskList.length > 1) {
// this.changeLayout('A|B')
// } else {
// this.changeLayout('A')
// // this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries)
// }
// } else {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries)
// // this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries)
// }
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries)
this.$refs['measurementList'].initPage(dicomSeries)
})
},
loadLinkedImageStack(dicomSeries) {
this.currentDicomCanvasIndex = dicomSeries.canvasIndex
var canvasIndex = dicomSeries.canvasIndex
this.canvasObj[canvasIndex] = dicomSeries
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)
this.$refs['measurementList'].initPage(dicomSeries)
})
},
// 给显示的画布设置显示的序列信息
async getSeriesShowInCanvas(layout) {
const loading = this.$loading({ fullscreen: true })
if (layout.name === 'A') {
// 判断当前激活窗口是否有序列信息
if (this.activeSeries) {
this.seriesStack = [this.activeSeries]
this.currentDicomCanvasIndex = 0
await this.setCanvas(this.seriesStack)
loading.close()
} else {
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
this.getFirstSeries(this.visitTaskList[idx]).then(async serires => {
this.seriesStack = [serires]
this.currentDicomCanvasIndex = 0
await this.setCanvas(this.seriesStack)
loading.close()
})
}
} else if (layout.name === 'A|A') {
if (this.activeSeries) {
this.seriesStack = [this.activeSeries, this.activeSeries]
this.currentDicomCanvasIndex = 0
await this.setCanvas(this.seriesStack)
loading.close()
} else {
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
this.getFirstSeries(this.visitTaskList[idx]).then(async serires => {
this.seriesStack = [serires, serires]
this.currentDicomCanvasIndex = 0
await this.setCanvas(this.seriesStack)
loading.close()
})
}
} else if (layout.name === 'A|B') {
if (this.activeSeries) {
const idx = this.visitTaskList.findIndex(i => i.VisitTaskId === this.activeSeries.visitTaskId)
const visitTaskNum = this.visitTaskList[idx].VisitTaskNum
if (visitTaskNum > 0 && this.visitTaskList.length > 1) {
const baseIdx = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
this.getFirstSeries(this.visitTaskList[this.CriterionType === 10 ? visitTaskNum - 1 : baseIdx]).then(async baseSerires => {
this.seriesStack = [baseSerires, this.activeSeries]
this.currentDicomCanvasIndex = 1
await this.setCanvas(this.seriesStack)
loading.close()
})
} else {
this.seriesStack = [this.activeSeries, this.activeSeries]
this.currentDicomCanvasIndex = 1
await this.setCanvas(this.seriesStack)
loading.close()
}
} else {
// 初始化
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
const visitTaskNum = this.visitTaskList[idx].VisitTaskNum
if (visitTaskNum > 0) {
// 随访
const baseIdx = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
this.getFirstSeries(this.visitTaskList[baseIdx]).then(baseSerires => {
this.getFirstSeries(this.visitTaskList[idx]).then(async serires => {
serires.ww = baseSerires.ww
serires.wc = baseSerires.wc
this.seriesStack = [baseSerires, serires]
this.currentDicomCanvasIndex = 1
await this.setCanvas(this.seriesStack)
loading.close()
})
})
} else {
// 基线
this.getFirstSeries(this.visitTaskList[idx]).then(async serires => {
this.seriesStack = [serires, serires]
this.currentDicomCanvasIndex = 1
await this.setCanvas(this.seriesStack)
loading.close()
})
}
}
} else if (layout.name === 'A|A|A|A') {
if (this.activeSeries) {
this.seriesStack = [this.activeSeries, this.activeSeries, this.activeSeries, this.activeSeries]
this.currentDicomCanvasIndex = 0
await this.setCanvas(this.seriesStack)
loading.close()
} else {
const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
this.getFirstSeries(this.visitTaskList[idx]).then(async serires => {
this.seriesStack = [serires, serires, serires, serires]
this.currentDicomCanvasIndex = 0
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() })
})
},
// 根据病灶标识定位图像
async imageLocation(obj) {
var loading = null
var loadImagePromises = []
var isScrollSync = this.isScrollSync
var isActiveSeriesExistMark = false
if (this.isScrollSync) {
// 取消滚动同步
this.isScrollSync = false
}
// 激活的窗口
var activeCanvasTaskId = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack.visitTaskId
var firstSeries = this.getSeriesInfoByMark(activeCanvasTaskId, obj)
if (firstSeries) {
DicomEvent.$emit('activeSeries', firstSeries)
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].isSetWwc = false
loadImagePromises.push(this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(firstSeries))
isActiveSeriesExistMark = true
} else {
firstSeries = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].series
}
// 非激活窗口
for (let i = 0; i < this.maxCanvas; i++) {
if (i !== this.currentDicomCanvasIndex && this.$refs[`dicomCanvas${i}`][0].stack && this.$refs[`dicomCanvas${i}`][0].stack.seriesId) {
var visitTaskId = this.$refs[`dicomCanvas${i}`][0].stack.visitTaskId
// 新病灶 || 基线病灶obj.lesionType === 2 || obj.lesionType === 4 既往新病灶
if ((this.CriterionType === 1) || (this.CriterionType === 10)) {
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === activeCanvasTaskId)
var idx = -1
if (this.CriterionType === 10) {
idx = this.visitTaskList[index].MeasureData.findIndex(item => {
return item.OrderMarkName === obj.lesionName
})
if (idx > -1) {
visitTaskId = this.visitTaskList[index].MeasureData[idx].FristAddTaskId
}
} else {
idx = this.visitTaskList[index].MeasureData.findIndex(item => item.QuestionId === obj.questionId && item.RowIndex === obj.rowIndex)
if (idx > -1) {
visitTaskId = this.visitTaskList[index].MeasureData[idx].FristAddTaskId
}
}
}
var taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
if (this.visitTaskList[taskIdx].VisitTaskId && !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 })
}
var secondSeries = this.getSeriesInfoByMark(visitTaskId, obj)
if (!secondSeries) {
secondSeries = this.getLinkedSeries(firstSeries, visitTaskId)
if (!secondSeries || secondSeries.seriesId === this.$refs[`dicomCanvas${i}`][0].series.seriesId) {
secondSeries = this.$refs[`dicomCanvas${i}`][0].series
} else {
secondSeries = secondSeries || this.$refs[`dicomCanvas${i}`][0].series
}
}
DicomEvent.$emit('activeSeries', secondSeries)
loadImagePromises.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(secondSeries))
if (!isActiveSeriesExistMark && secondSeries) {
const activeTaskId = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack.visitTaskId
var canvasIdx = this.currentDicomCanvasIndex === 0 ? 1 : 0
if (i === canvasIdx) {
const series = this.getLinkedSeries(this.$refs[`dicomCanvas${canvasIdx}`][0].series, activeTaskId)
if (series) {
loadImagePromises.push(this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(series))
DicomEvent.$emit('activeSeries', series)
}
}
}
}
}
Promise.all(loadImagePromises)
.then(() => {
this.isScrollSync = isScrollSync
})
if (loading) {
loading.close()
}
},
selectViewCanvas(offset) {
var canvasIndex = this.currentDicomCanvasIndex + offset
if (canvasIndex < 0 || canvasIndex >= this.maxCanvas) return
this.activateDicomCanvas(canvasIndex)
},
// 废弃
imageLocation1(obj) {
var isScrollSync = this.isScrollSync
if (this.isScrollSync) {
// 取消滚动同步
this.isScrollSync = false
}
if (this.layout === 'A|B') {
// 新病灶,视图显示新病灶第一次出现时访视下的序列,
// 第一个视图所在的任务有标记,第二个视图所在的任务无标记时,第二个任务与第一个任务对齐
if (this.$refs[`dicomCanvas0`][0].stack && this.$refs[`dicomCanvas0`][0].stack.seriesId) {
const firstVisitTaskId = this.$refs[`dicomCanvas0`][0].stack.visitTaskId
const firstSeries = this.getSeriesInfoByMark(firstVisitTaskId, obj)
console.log('firstSeries', firstSeries)
if (firstSeries && this.$refs[`dicomCanvas1`][0].stack && this.$refs[`dicomCanvas1`][0].stack.seriesId) {
const secondVisitTaskId = this.$refs[`dicomCanvas1`][0].stack.visitTaskId
const secondSeries = this.getSeriesInfoByMark(secondVisitTaskId, obj)
console.log('secondSeries', secondSeries)
if (!secondSeries) {
var loadImagePromises = [this.$refs[`dicomCanvas0`][0].loadImageStack(firstSeries)]
DicomEvent.$emit('activeSeries', firstSeries)
this.$refs[`dicomCanvas0`][0].isSetWwc = false
var seriesInfo = this.getLinkedSeries(firstSeries, secondVisitTaskId)
if (Object.keys(seriesInfo).length !== 0) {
loadImagePromises.push(this.$refs[`dicomCanvas1`][0].loadImageStack(seriesInfo.series))
DicomEvent.$emit('activeSeries', seriesInfo)
this.$refs[`dicomCanvas1`][0].isSetWwc = false
}
Promise.all(loadImagePromises)
.then(() => {
this.isScrollSync = isScrollSync
})
return
}
}
}
}
// 根据病灶标识T01所有canvas都跳转到当前canvas所属任务下T01所在的影像没有则不处理
var loadImagePromiseArr = []
for (let i = 0; i < this.maxCanvas; i++) {
if (this.$refs[`dicomCanvas${i}`][0].stack && this.$refs[`dicomCanvas${i}`][0].stack.seriesId) {
var visitTaskId = this.$refs[`dicomCanvas${i}`][0].stack.visitTaskId
// 根据任务ID测量病灶信息
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
if (index > -1 && this.visitTaskList[index].measureDataInit) {
var idx = -1
if (this.CriterionType === 10) {
idx = this.visitTaskList[index].MeasureData.findIndex(item => {
return 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]
// var instanceIdx = series.imageIds.findIndex(imageId => !!~imageId.indexOf(instanceId))
var instanceIdx = series.instanceList.findIndex(imageId => !!~imageId.indexOf(instanceId))
if (instanceIdx > -1) {
series.imageIdIndex = instanceIdx
this.$refs[`dicomCanvas${i}`][0].isSetWwc = false
loadImagePromiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(series))
DicomEvent.$emit('activeSeries', { visitTaskId: visitTaskId, studyId, studyIndex: studyIdx, seriesIndex: series.seriesIndex })
}
}
}
}
}
}
}
Promise.all(loadImagePromiseArr)
.then(() => {
this.isScrollSync = isScrollSync
})
},
// 根据标记获取标记所在的序列信息
getSeriesInfoByMark(visitTaskId, obj) {
var seriesInfo = null
// 根据任务ID测量病灶信息
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
if (index > -1) {
var idx = -1
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]
// var instanceIdx = series.imageIds.findIndex(imageId => !!~imageId.indexOf(instanceId))
var instanceIdx = series.instanceList.findIndex(imageId => !!~imageId.indexOf(instanceId))
if (instanceIdx > -1) {
series.imageIdIndex = instanceIdx
// series.studyIndex = studyIdx
// series.seriesIndex = seriesIdx
// this.$refs[`dicomCanvas${i}`][0].isSetWwc = false
// loadImagePromiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(series))
// series.visitTaskId = visitTaskId
// series.studyId = studyId
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.85 ? similarArr[0].index : -1
if (i > -1) {
obj = seriesList[i]
}
// const idx = seriesList.findIndex(series => series.description === baseSeries.description)
// idx > -1 ? obj = seriesList[idx] : ''
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 idx = seriesList.findIndex(series => series.isDicom && series.instanceCount > 0)
// idx > -1 ? obj = seriesList[idx] : ''
// }
if (obj) {
obj.imageIdIndex = Math.floor(obj.imageIds.length * (baseSeries.imageIdIndex / baseSeries.instanceCount))
}
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)
},
getLinkedSeries1(baseSeries, visitTaskId) {
var index = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
var visitTaskInfo = this.visitTaskList[index]
var obj = {}
var studyList = visitTaskInfo.StudyList
// 筛选描述一致
var seriseArr = []
studyList.forEach((s, i) => {
var series = s.SeriesList.filter(series => series.description === baseSeries.description)
series.length > 0 ? seriseArr.push(...series) : ''
})
if (seriseArr.length > 0) {
// 描述一致,则筛选层厚一致
var stSeriseArr = seriseArr.filter(s => s.sliceThickness === baseSeries.sliceThickness)
if (stSeriseArr.length > 0) {
// 层厚一致,则筛选图像数量一致
var icSeriseArr = stSeriseArr.filter(s => s.instanceCount === baseSeries.instanceCount)
if (icSeriseArr.length > 0) {
const sIdx = icSeriseArr[0].studyIndex
const series = icSeriseArr[0]
var imageIdIndex = Math.floor(series.imageIds.length * (baseSeries.imageIdIndex / baseSeries.instanceCount))
obj.studyId = series.studyId
obj.studyIndex = sIdx
obj.seriesIndex = series.seriesIndex
obj.series = series
obj.series.imageIdIndex = imageIdIndex
obj.seriesId = series.seriesId
obj.visitTaskId = visitTaskId
} else {
const sIdx = stSeriseArr[0].studyIndex
const series = stSeriseArr[0]
const imageIdIndex = Math.floor(series.imageIds.length * (baseSeries.imageIdIndex / baseSeries.instanceCount))
obj.studyIndex = sIdx
obj.studyId = series.studyId
obj.seriesIndex = series.seriesIndex
obj.series = series
obj.series.imageIdIndex = imageIdIndex
obj.seriesId = series.seriesId
obj.visitTaskId = visitTaskId
}
} else {
const sIdx = seriseArr[0].studyIndex
const series = seriseArr[0]
const imageIdIndex = Math.floor(series.imageIds.length * (baseSeries.imageIdIndex / baseSeries.instanceCount))
obj.studyIndex = sIdx
obj.studyId = series.studyId
obj.seriesIndex = series.seriesIndex
obj.series = series
obj.series.imageIdIndex = imageIdIndex
obj.seriesId = series.seriesId
obj.visitTaskId = visitTaskId
}
} else {
// if (!this.isFirstNotLinked) {
// this.isFirstNotLinked = true
// // 都不符合要求, 判断是否存在层厚为5的序列否则显示第一个检查的第一个序列
// var seriesObj = null
// for (let i = 0; i < studyList.length; i++) {
// const seriesIdx = studyList[i].SeriesList.findIndex(s => s.sliceThickness && parseInt(s.sliceThickness) === 5)
// if (seriesIdx > -1) {
// seriesObj = { studyIndex: i, seriesIdx, series: studyList[i].SeriesList[seriesIdx] }
// break
// }
// }
// if (seriesObj) {
// obj.studyIndex = seriesObj.studyIndex
// obj.seriesIndex = seriesObj.seriesIdx
// seriesObj.series.imageIdIndex = Math.floor(seriesObj.series.imageIds.length / 2)
// obj.series = seriesObj.series
// obj.seriesId = seriesObj.series.seriesId
// } else {
// const sIdx = studyList.findIndex(s => s.IsDicom)
// const series = studyList[sIdx].SeriesList[0]
// series.imageIdIndex = Math.floor(series.imageIds.length / 2)
// obj.studyIndex = sIdx
// obj.seriesIndex = 0
// obj.series = series
// obj.seriesId = series.seriesId
// }
// }
}
return obj
},
// 获取某个任务下第一个序列信息
async getFirstSeries(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) {
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)
})
},
// 更新画布
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(true, false, 0, type)
} else if (type === 3) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, true, 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) {
if (index !== this.currentDicomCanvasIndex) {
var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
this.activeSeries = dicomSeries
if (this.activeTool) {
if (dicomSeries.isCurrentTask && dicomSeries.readingTaskState < 2) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
} else {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
}
this.activeTool = ''
}
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'
}
var stack = this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].stack
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`].focus()
if (stack.studyId) {
DicomEvent.$emit('toggleVisitList', stack)
}
}
},
// 鼠标移入测量工具时,判断工具是否可激活
enter(e, toolName) {
var i = this.measuredTools.findIndex(item => item.toolName === toolName)
if (i === -1) return
var dicomSeries = this.canvasObj[this.currentDicomCanvasIndex]
if (dicomSeries && (!dicomSeries.isCurrentTask || dicomSeries.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) {
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'
}
}
},
// 设置测量工具启用(不会对输入作出反应)
setToolActive(toolName, isMeasuredTool, e, type) {
console.log('setToolActive', toolName)
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 && !type) {
this.measuredTools.forEach(item => {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(item.toolName)
})
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
// this.activeTool = ''
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
},
// 添加标记
setMeasureData(data) {
this.$refs['measurementList'].setMeasuredData(data)
this.activeTool = ''
},
// 修改标记
modifyMeasureData(data) {
this.$refs['measurementList'].modifyMeasuredData(data)
this.activeTool = ''
},
saveImage() {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].saveImage()
},
// 设置窗宽/窗位
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() {
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
// if (this.isImageIndexSync) {
// for (var i = 0; i < this.maxCanvas; i++) {
// if (i === this.currentDicomCanvasIndex) {
// this.imageIndexSync.sourceCanvas = this.$refs[`dicomCanvas${i}`][0].canvas
// } else {
// this.imageIndexSync.targetCanvas.push(this.$refs[`dicomCanvas${i}`][0].canvas)
// }
// }
// }
},
scrollSync(obj) {
for (var i = 0; i < this.maxCanvas; i++) {
if (i !== obj.canvasIndex) {
this.$refs[`dicomCanvas${i}`][0].scrollPage(obj.direction)
}
}
},
// setImageIndexSync() {
// this.isImageIndexSync = !this.isImageIndexSync
// if (!this.imageIndexSync) {
// this.imageIndexSync = new cornerstoneTools.Synchronizer(
// 'cornerstonenewimage',
// cornerstoneTools.stackImagePositionOffsetSynchronizer
// )
// for (var i = 0; i < this.maxCanvas; i++) {
// if (i === this.currentDicomCanvasIndex) {
// this.imageIndexSync.add(this.$refs[`dicomCanvas${i}`][0].canvas)
// } else {
// this.imageIndexSync.add(this.$refs[`dicomCanvas${i}`][0].canvas)
// }
// }
// this.imageIndexSync.enabled = true
// } else {
// this.imageIndexSync.destroy()
// this.imageIndexSync = null
// }
// },
showPanel(e) {
e.currentTarget.firstChild.lastChild.style.display = 'block'
},
handleMouseout(e) {
e.currentTarget.firstChild.lastChild.style.display = 'none'
},
// 预览临床数据
previewCD() {
// const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
// if (idx > -1) {
// if (this.visitTaskList[idx].ReadingTaskState < 2) {
// var visitTaskId = this.visitTaskList[idx].VisitTaskId
// readClinicalData({ visitTaskId }).then(res => {
// console.log(res)
// })
// }
// }
this.$emit('previewCD')
},
previewNoneDicoms() {
this.$emit('previewNoneDicoms')
}
}
}
</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: 30px;
.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_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 0px;
}
}
}
ul li:hover a{
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;
border: 1px dashed #fff;
}
}
}
.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%
// }
}
}
</style>