irc_web/.svn/pristine/7d/7d79cc424b6b663bd3adce24eed...

733 lines
24 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">
<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">
<ul style="width:40px">
<li v-for="layout in layouts" :key="layout.index">
<a href="#" @click.prevent="changeLayout(layout)">{{ layout.row }}*{{ layout.col }}</a>
</li>
</ul>
</div>
</div>
</div>
<div class="tool-wrapper">
<div
class="icon"
:class="[activeTool==='Wwwc'?'tool_active':'']"
data-tool="Wwwc"
@click.prevent="setToolActive('Wwwc',false)"
>
<svg-icon icon-class="reversecolor" class="svg-icon" />
</div>
<div class="text">窗宽/窗位</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">
<div class="dropdown">
<div class="icon" data-tool="Rotate" @click.prevent="setToolActive('Rotate',false)">
<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"
@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 class="tool-wrapper">
<div
class="icon"
:class="[activeTool==='Length'?'tool_active':'']"
data-tool="Length"
@click.prevent="setToolActive('Length',true)"
@mouseenter="enter($event,'Length')"
>
<svg-icon icon-class="length" class="svg-icon" />
</div>
<div class="text">长径测量</div>
</div>
<div class="tool-wrapper">
<div
class="icon"
:class="[activeTool==='Bidirectional'?'tool_active':'']"
data-tool="Bidirectional"
@click.prevent="setToolActive('Bidirectional',true)"
@mouseenter="enter($event,'Bidirectional')"
>
<svg-icon icon-class="bidirection" class="svg-icon" />
</div>
<div class="text">长短径测量</div>
</div>
<div class="tool-wrapper">
<div
class="icon"
:class="[activeTool==='ArrowAnnotate'?'tool_active':'']"
data-tool="ArrowAnnotate"
@click.prevent="setToolActive('ArrowAnnotate',true)"
@mouseenter="enter($event,'ArrowAnnotate')"
>
<svg-icon icon-class="label" class="svg-icon" />
</div>
<div class="text">标注</div>
</div> -->
<!-- <div class="tool-wrapper">
<div
class="icon"
:class="[activeTool==='Eraser'?'tool_active':'']"
data-tool="Eraser"
@click.prevent="setToolActive('Eraser')"
>
<svg-icon icon-class="clear" class="svg-icon" />
</div>
<div class="text">清除标记</div>
</div> -->
<!-- <div class="tool-wrapper">
<div class="dropdown">
<div class="icon">
<svg-icon icon-class="more" class="svg-icon" />
</div>
<div class="text">更多<i class="el-icon-caret-bottom" /></div>
<div class="dropdown-content">
<ul style="width:90px;text-align: left;">
<li>
<a href="#">
<svg-icon icon-class="angle" />
角度测量
</a>
</li>
<li>
<a href="#">
<svg-icon icon-class="cobb" />
Cobb测量
</a>
</li>
<li>
<a href="#">
<svg-icon icon-class="oval" />
椭圆测量
</a>
</li>
<li>
<a href="#">
<svg-icon icon-class="rectangle" />
矩形测量
</a>
</li>
<li>
<a href="#">
<svg-icon icon-class="image" />
导出Png图像
</a>
</li>
</ul>
</div>
</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"
@click="activateDicomCanvas(i-1)"
>
<dicom-canvas
v-if="canvasW"
:ref="`dicomCanvas${i-1}`"
:style="{width:canvasW,height: canvasH}"
:is-current-task="isCurrentTask"
:is-active="i-1===currentDicomCanvasIndex"
@setMeasureData="setMeasureData"
@removeMeasureData="removeMeasureData"
@modifyMeasureData="modifyMeasureData"
/>
</div>
</div>
<div ref="form-container" class="form-container">
<MeasurementList
v-if="visitTaskId"
ref="measurementList"
:is-current-task="isCurrentTask"
/>
</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 Store from './Store'
export default {
name: 'DicomViewer',
components: { DicomCanvas, MeasurementList },
props: {
visitTaskId: {
type: String,
default: ''
},
isCurrentTask: {
type: Boolean,
required: true
},
readingTaskState: {
type: Number,
required: true
}
},
data() {
return {
layouts: [
{ index: 0, row: 1, col: 1 },
{ index: 1, row: 1, col: 2 }
// { 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: 0,
currentDicomCanvas: {
toolState: {
clipPlaying: false
}
},
colormapsList: [],
rotateList: [],
colorList: [],
wwwcList: [],
canvasW: null,
canvasH: null,
activeTool: '',
// measuredTools: ['Length', 'Bidirectional', 'ArrowAnnotate'],
measuredTools: [
{ toolName: 'Length', text: '长径测量', icon: 'length', isDisabled: false, disabledReason: '' },
{ toolName: 'Bidirectional', text: '长短径测量', icon: 'bidirection', isDisabled: false, disabledReason: '' },
{ toolName: 'ArrowAnnotate', text: '标注', icon: 'label', isDisabled: false, disabledReason: '' }],
fitType: 0,
isDisabledTool: false
}
},
mounted() {
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.setCanvasStyle()
window.addEventListener('resize', this.setCanvasStyle)
Store.$on('updateImage', (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].updateImage(measureData)
}
}
console.log('updateImage')
})
Store.$on('removeToolState', (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)
}
}
console.log('removeToolState')
})
},
beforeDestroy() {
Store.$off('updateImage')
Store.$off('removeToolState')
},
methods: {
loadImageStack(dicomSeries) {
if (this.activeTool) {
if (this.isCurrentTask && this.readingTaskState < 2) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(this.activeTool)
} else {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(this.activeTool)
}
this.activeTool = ''
}
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].loadImageStack(dicomSeries)
},
// 设置画布大小
setCanvasStyle() {
this.canvasW = (window.innerWidth - 570) / this.layoutCol + 'px'
this.canvasH = (window.innerHeight - 130) / this.layoutRow + 'px'
},
// 切换布局
changeLayout(layout) {
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)
})
})
},
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)
} else if (type === 3) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, true, 0)
} else if (type === 4) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, -90)
} else if (type === 5) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setRotate(false, false, 90)
}
},
// 激活画布
activateDicomCanvas(index) {
if (index !== this.currentDicomCanvasIndex) {
if (this.activeTool) {
if (this.isCurrentTask && this.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) {
Store.$emit('toggleVisitList', stack)
}
}
},
enter(e, toolName) {
var i = this.measuredTools.findIndex(item => item.toolName === toolName)
if (i === -1) return
if (!this.isCurrentTask || this.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)
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) {
console.log('setToolActive')
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
if (this.isCurrentTask && isMeasuredTool && this.readingTaskState < 2) {
if (this.activeTool && this.activeTool === toolName) {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
this.activeTool = ''
} else {
this.activeTool = toolName
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
}
} else {
if (!this.activeTool) return
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolEnabled(toolName)
this.activeTool = ''
}
// if (this.isCurrentTask && isMeasuredTool && this.readingTaskState < 2) {
// // 未签名的当前任务可操作
// if (this.activeTool === toolName) {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
// this.activeTool = ''
// } else {
// if (this.measuredTools.findIndex(i => i.toolName === toolName) > -1) {
// // 当前状态是否可添加标记
// var isCanActiveTool = this.$refs['measurementList'].isCanActiveTool(toolName)
// if (isCanActiveTool) {
// this.activeTool = toolName
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
// } else {
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolPassive(toolName)
// this.activeTool = ''
// }
// } else {
// this.activeTool = toolName
// this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`][0].setToolActive(toolName)
// }
// }
// } else {
// if (this.activeTool) {
// 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() {
if (!this.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 = ''
},
removeMeasureData(uuid) {
console.log(uuid)
},
modifyMeasureData(data) {
this.$refs['measurementList'].modifyMeasuredData(data)
this.activeTool = ''
}
}
}
</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;
}
}
.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;
}
}
}
.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>