1085 lines
38 KiB
Plaintext
1085 lines
38 KiB
Plaintext
<template>
|
||
<div class="dicom-viewer-wrapper">
|
||
<div class="dicom-viewer-container">
|
||
<div class="dicom-tools">
|
||
|
||
<div class="tool-wrapper">
|
||
<div class="dropdown">
|
||
<div class="icon">
|
||
<svg-icon icon-class="layout" class="svg-icon" />
|
||
</div>
|
||
<div class="text">布局<i class="el-icon-caret-bottom" /></div>
|
||
<div class="dropdown-content layout-content">
|
||
<ul style="width:50px">
|
||
<li class="flex_row" @click.prevent="changeLayout('A')">
|
||
<div class="layout_box_1_1">
|
||
A
|
||
</div>
|
||
</li>
|
||
<li class="flex_row" @click.prevent="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.prevent="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.prevent="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>
|
||
|
||
<div class="tool-wrapper">
|
||
<div class="dropdown">
|
||
<div
|
||
class="icon"
|
||
data-tool="Wwwc"
|
||
:class="[activeTool==='Wwwc'?'tool_active':'']"
|
||
style=" width: 35px;translate: 50%;"
|
||
@click.prevent="setToolActive('Wwwc',false)"
|
||
>
|
||
<svg-icon icon-class="reversecolor" class="svg-icon" />
|
||
</div>
|
||
<div class="text">窗宽/窗位<i class="el-icon-caret-bottom" /></div>
|
||
<div class="dropdown-content">
|
||
<ul style="width:80px">
|
||
<li v-for="item in wwwcArr" :key="item.label">
|
||
<a href="#" @click.prevent="setDicomCanvasWwwc(item)">{{ item.label }}</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<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">缩放</div>
|
||
</div>
|
||
|
||
<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">移动</div>
|
||
</div>
|
||
|
||
<div class="tool-wrapper">
|
||
<!-- @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" />
|
||
</div>
|
||
<div class="text">旋转<i class="el-icon-caret-bottom" /></div>
|
||
<div class="dropdown-content">
|
||
<ul style="width:80px">
|
||
<li v-for="rotate in rotateArr" :key="rotate.label">
|
||
<a href="#" @click.prevent="setDicomCanvasRotate(rotate.val)">{{ rotate.label }}</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<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?'适应窗口':'适应图像' }}</div>
|
||
</div>
|
||
|
||
<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">同步</div>
|
||
</div>
|
||
<!--
|
||
<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> -->
|
||
<div
|
||
v-for="tool in measuredTools"
|
||
:key="tool.toolName"
|
||
>
|
||
<el-tooltip v-if="tool.disabledReason" class="item" effect="dark" :content="tool.disabledReason" placement="top">
|
||
<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">临床数据</el-button>
|
||
<!-- <el-button v-if="isExistsNoDicomFile" type="text" @click="previewNoneDicoms">非Dicom文件</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"
|
||
@setMeasureData="setMeasureData"
|
||
@modifyMeasureData="modifyMeasureData"
|
||
@scrollSync="scrollSync"
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div ref="form-container" class="form-container">
|
||
<!-- 激活canvas测量数据 -->
|
||
<MeasurementList
|
||
ref="measurementList"
|
||
/>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</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 MeasurementList from './MeasurementList'
|
||
import DicomEvent from './DicomEvent'
|
||
import { mapGetters } from 'vuex'
|
||
import store from '@/store'
|
||
export default {
|
||
name: 'DicomViewer',
|
||
components: { DicomCanvas, MeasurementList },
|
||
props: {
|
||
isExistsClinicalData: {
|
||
type: Boolean,
|
||
default: false
|
||
},
|
||
isExistsNoDicomFile: {
|
||
type: Boolean,
|
||
default: false
|
||
}
|
||
},
|
||
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: '默认值', val: 1 },
|
||
{ label: '垂直翻转', val: 2 },
|
||
{ label: '水平翻转', val: 3 },
|
||
{ label: '左转90度', val: 4 },
|
||
{ label: '右转90度', val: 5 }
|
||
],
|
||
maxCanvas: 1,
|
||
layoutRow: 1,
|
||
layoutCol: 1,
|
||
currentDicomCanvasIndex: -1,
|
||
currentDicomCanvas: {
|
||
toolState: {
|
||
clipPlaying: false
|
||
}
|
||
},
|
||
colormapsList: [],
|
||
rotateList: [],
|
||
colorList: [],
|
||
wwwcList: [],
|
||
canvasW: null,
|
||
canvasH: null,
|
||
activeTool: '',
|
||
CriterionType: 0,
|
||
measuredTools: [
|
||
{ toolName: 'Length', text: '直径测量', icon: 'length', isDisabled: false, disabledReason: '' },
|
||
{ toolName: 'Bidirectional', text: '长短径测量', icon: 'bidirection', isDisabled: false, disabledReason: '' },
|
||
{ toolName: 'ArrowAnnotate', text: '箭头工具', icon: 'arrow', isDisabled: false, disabledReason: '' }],
|
||
fitType: 0,
|
||
isDisabledTool: false,
|
||
canvasObj: {},
|
||
wwwcArr: [
|
||
{ label: '默认值', val: 1, ww: null, wc: null },
|
||
{ label: 'CT Abdomen', val: 2, wc: 60, ww: 400 },
|
||
{ label: 'CT Angio', val: 3, wc: 300, ww: 600 },
|
||
{ label: 'CT Bone', val: 4, wc: 300, ww: 1500 },
|
||
{ label: 'CT Brain', val: 5, wc: 40, ww: 80 },
|
||
{ label: 'CT Chest', val: 6, wc: 40, ww: 400 },
|
||
{ label: 'CT Lungs', val: 7, wc: -400, ww: 1500 }
|
||
],
|
||
activeSeries: {},
|
||
seriesStack: [],
|
||
trialId: '',
|
||
isScrollSync: false,
|
||
imageIndexSync: {
|
||
sourceCanvas: '',
|
||
targetCanvas: []
|
||
},
|
||
isFirstRender: false,
|
||
isReadingTaskViewInOrder: false
|
||
}
|
||
},
|
||
computed: {
|
||
...mapGetters(['visitTaskList'])
|
||
},
|
||
mounted() {
|
||
this.isReadingTaskViewInOrder = this.$router.currentRoute.query.isReadingTaskViewInOrder === 'true'
|
||
this.CriterionType = parseInt(localStorage.getItem('CriterionType'))
|
||
if (this.CriterionType === 10) {
|
||
this.measuredTools = [{ toolName: 'ArrowAnnotate', text: '箭头', icon: 'label', 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.studyId) {
|
||
this.$refs[`dicomCanvas${i}`][0].getMeasureData()
|
||
}
|
||
}
|
||
console.log('getMeasureData')
|
||
})
|
||
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')
|
||
})
|
||
},
|
||
beforeDestroy() {
|
||
DicomEvent.$off('updateImage')
|
||
DicomEvent.$off('getMeasureData')
|
||
DicomEvent.$off('imageLocation')
|
||
DicomEvent.$off('setReadingState')
|
||
},
|
||
methods: {
|
||
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()
|
||
})
|
||
},
|
||
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
|
||
if (!this.isFirstRender || dicomSeries.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['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 => {
|
||
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(() => {
|
||
resolve()
|
||
}).catch(() => { resolve() })
|
||
})
|
||
},
|
||
// 根据病灶标识定位图像
|
||
imageLocation(obj) {
|
||
console.log(obj)
|
||
var isScrollSync = this.isScrollSync
|
||
if (this.isScrollSync) {
|
||
// 取消滚动同步
|
||
this.isScrollSync = false
|
||
}
|
||
// 根据病灶标识(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 = this.visitTaskList[index].MeasureData.findIndex(item => item.QuestionId === obj.questionId && item.RowIndex === obj.rowIndex)
|
||
if (idx > -1) {
|
||
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))
|
||
if (instanceIdx > -1) {
|
||
series.imageIdIndex = instanceIdx
|
||
loadImagePromiseArr.push(this.$refs[`dicomCanvas${i}`][0].loadImageStack(series))
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
Promise.all(loadImagePromiseArr)
|
||
.then(() => {
|
||
this.isScrollSync = isScrollSync
|
||
})
|
||
},
|
||
// 获取某个任务下第一个序列信息
|
||
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) {
|
||
return studyList[idx].SeriesList[0]
|
||
} else {
|
||
return ''
|
||
}
|
||
},
|
||
|
||
// 设置画布大小
|
||
setCanvasStyle() {
|
||
this.canvasW = (window.innerWidth - 570) / this.layoutCol + 'px'
|
||
this.canvasH = (window.innerHeight - 130) / this.layoutRow + 'px'
|
||
},
|
||
// 切换布局
|
||
changeLayout(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
|
||
|
||
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 = ''
|
||
} 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 = ''
|
||
},
|
||
// 设置窗宽/窗位
|
||
setDicomCanvasWwwc(v) {
|
||
if (v.val === 1) {
|
||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].resetWwwc()
|
||
} else if (v.val === 8) {
|
||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].toggleInvert()
|
||
} else {
|
||
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setWwwc(v.ww, v.wc)
|
||
}
|
||
},
|
||
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
|
||
// }
|
||
// },
|
||
// 预览临床数据
|
||
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;
|
||
|
||
.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;
|
||
}
|
||
}
|
||
.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: 1;
|
||
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>
|