irc_web/src/components/Dicom/DicomViewer.vue

1530 lines
54 KiB
Vue
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 ref="dicom-wrapper" class="dicom-wrapper">
<div ref="dicomViewer" class="dicom-viewer">
<!-- <div v-for="i in layoutRow" :key="i" class="dicom-row" :style="{height: rowHeight}">
<div v-for="j in layoutCol" :key="j" class="dicom-item" oncontextmenu="return false">
<dicom-canvas ref="dicomCanvas" style="width:100%;height:100%" />
</div>
</div>-->
<div class="Anonymous" v-if="isAnonymous">
<div
:class="{ btn: true, activeBtn: activeTool === 'Note_RectangleRoi' && !isComparison, isNoted: isComparison }"
@click="setToolActive($event, 'Note_RectangleRoi')">{{
$t('DicomViewer:anonymous:Note_RectangleRoi') }}</div>
<div :class="{ btn: true, activeBtn: activeTool === 'Eraser' && !isComparison, isNoted: isComparison }"
@click="setToolActive($event, 'Eraser')">{{
$t('DicomViewer:anonymous:Eraser') }}
</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(false)">{{
$t('DicomViewer:anonymous:Application') }}</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="anonymousImage(true)">{{
$t('DicomViewer:anonymous:ApplicationAll') }}</div>
<!-- <div class="btn">刷新图像</div> -->
<div class="btn" v-if="!isComparison" @click="comparison(true)">{{
$t('DicomViewer:anonymous:Comparison') }}</div>
<div class="btn" v-else @click="comparison(false)">{{
$t('DicomViewer:anonymous:Exit') }}</div>
<div :class="{ btn: true, isNoted: isComparison }" @click="recovery(false)">{{
$t('DicomViewer:anonymous:Recovery') }}</div>
</div>
<div v-show="layoutRow >= 1" class="dicom-row" :style="{ height: rowHeight }">
<div v-show="layoutRow >= 1 && layoutCol >= 1" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas0' }" data-index="0" @click="activateDicomCanvas(0)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas0" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow >= 1 && layoutCol >= 2" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas1' }" data-index="1" @click="activateDicomCanvas(1)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas1" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow >= 1 && layoutCol >= 3" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas2' }" data-index="2" @click="activateDicomCanvas(2)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas2" style="width:100%;height:100%" />
</div>
</div>
<div v-show="layoutRow >= 2" class="dicom-row" :style="{ height: rowHeight }">
<div v-show="layoutRow >= 2 && layoutCol >= 1" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas3' }" data-index="3" @click="activateDicomCanvas(3)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas3" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow >= 2 && layoutCol >= 2" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas4' }" data-index="4" @click="activateDicomCanvas(4)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas4" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow >= 2 && layoutCol >= 3" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas5' }" data-index="5" @click="activateDicomCanvas(5)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas5" style="width:100%;height:100%" />
</div>
</div>
<div v-show="layoutRow == 3" class="dicom-row" :style="{ height: rowHeight }">
<div v-show="layoutRow == 3 && layoutCol >= 1" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas6' }" data-index="6" @click="activateDicomCanvas(6)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas6" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow == 3 && layoutCol >= 2" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas7' }" data-index="7" @click="activateDicomCanvas(7)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas7" style="width:100%;height:100%" />
</div>
<div v-show="layoutRow == 3 && layoutCol >= 3" class="dicom-item"
:class="{ 'activeItem': activeItem == 'dicomCanvas8' }" data-index="8" @click="activateDicomCanvas(8)"
@dblclick="setFullScreen($event)">
<dicom-canvas ref="dicomCanvas8" style="width:100%;height:100%" />
</div>
</div>
</div>
<div ref="dicomTools" class="dicom-tools">
<!-- 布局 -->
<div class="measureTool-wrapper">
<div class="sideTool-title">{{ $t('trials:reading:button:layout') }}</div>
<div class="sideTool-wrapper">
<label>{{ $t('trials:reading:button:layout') }}:</label>
<select class="sidetool-select" style="width:90px" :disabled="isAnonymous" @change="changeLayout($event)">
<option value="1x1" selected>1x1</option>
<option value="1x2">1x2</option>
<option value="2x1">2x1</option>
<option value="2x2">2x2</option>
<option value="1x3">1x3</option>
<option value="3x1">3x1</option>
<option value="2x3">2x3</option>
<option value="3x2">3x2</option>
<option value="3x3">3x3</option>
</select>
<div class="btnBox" v-if="hasAnonymous" @click="openAnonymous">{{ $t('DicomViewer:anonymous:PixelAnonymity')
}}
</div>
</div>
</div>
<!-- 图像变换 -->
<div class="measureTool-wrapper">
<div class="sideTool-title">{{ $t('trials:dicom-show:transform') }}</div>
<div class="sideTool-wrapper">
<button :title="$t('trials:reading:button:wwwc')" class="btn-link" data-tool="Wwwc"
@click="setToolActive($event, 'Wwwc')">
<svg-icon icon-class="reverse" style="font-size:20px;" />
</button>
<!-- <button
title="区域调窗"
class="btn-link"
data-tool="WwwcRegion"
@click="setToolActive($event,'WwwcRegion')"
>
<svg-icon icon-class="wwwcRegion" style="font-size:20px;" />
</button>-->
<button :title="$t('trials:reading:button:reverseColor')" class="btn-link" @click="toggleInvert">
<svg-icon icon-class="reversecolor" style="font-size:20px;" />
</button>
<button :title="$t('trials:reading:button:zoom')" class="btn-link" data-tool="Zoom"
@click="setToolActive($event, 'Zoom')">
<svg-icon icon-class="magnifier" style="font-size:20px;" />
</button>
<button :title="$t('trials:dicom-show:lens')" class="btn-link" data-tool="Magnify"
@click="setToolActive($event, 'Magnify')">
<svg-icon icon-class="zoom" style="font-size:20px;" />
</button>
<button :title="$t('trials:reading:button:rotate')" class="btn-link dropdown" data-tool="Rotate">
<svg-icon icon-class="rotate" style="font-size:20px;" />
<div class="dropdown-content">
<div @click.stop="setDicomCanvasRotate(1)">{{ $t('trials:reading:button:rotateDefault') }}</div>
<div @click.stop="setDicomCanvasRotate(2)">{{ $t('trials:reading:button:rotateHorizontal') }}</div>
<div @click.stop="setDicomCanvasRotate(3)">{{ $t('trials:reading:button:rotateVertical') }}</div>
<div @click.stop="setDicomCanvasRotate(4)">{{ $t('trials:reading:button:rotateTurnLeft') }}</div>
<div @click.stop="setDicomCanvasRotate(5)">{{ $t('trials:reading:button:rotateTurnRight') }}</div>
</div>
</button>
<button :title="$t('trials:reading:button:move')" class="btn-link" data-tool="Pan"
@click="setToolActive($event, 'Pan')">
<svg-icon icon-class="move" style="font-size:20px;" />
</button>
<button :title="$t('trials:reading:button:fitWindow')" class="btn-link" data-tool="fitToWindow"
@click="fitToType($event, 'fitToWindow')">
<svg-icon icon-class="fitToWindow" style="font-size:20px;" />
</button>
<button :title="$t('trials:reading:button:fitImage')" class="btn-link" data-tool="fitToImage"
@click="fitToType($event, 'fitToImage')">
<svg-icon icon-class="fitToImage" style="font-size:20px;" />
</button>
<!-- <button title="旋转" class="btn-link dropdown" data-tool="Rotate" @click="setToolActive($event,'Rotate')"> -->
</div>
</div>
<!-- 测量标注 -->
<div class="measureTool-wrapper">
<div class="sideTool-title">{{ $t('trials:dicom-show:measurementLabeling') }}</div>
<div class="sideTool-wrapper">
<!-- 探针 -->
<button :title="$t('trials:dicom-show:Probe')" class="btn-link" data-tool="Probe"
@click="setToolActive($event, 'Probe')">
<svg-icon icon-class="pixel" style="font-size:20px;" />
</button>
<!-- 长度测量 -->
<button :title="$t('trials:dicom-show:Length')" class="btn-link" data-tool="Length"
@click="setToolActive($event, 'Length')">
<svg-icon icon-class="length" style="font-size:20px;" />
</button>
<!-- 角度测量 -->
<button :title="$t('trials:dicom-show:Angle')" class="btn-link" data-tool="Angle"
@click="setToolActive($event, 'Angle')">
<svg-icon icon-class="angle" style="font-size:20px;" />
</button>
<!-- Cobb测量 -->
<button :title="$t('trials:dicom-show:CobbAngle')" class="btn-link" data-tool="CobbAngle"
@click="setToolActive($event, 'CobbAngle')">
<svg-icon icon-class="cobb" style="font-size:20px;" />
</button>
<!-- 椭圆测量 -->
<button :title="$t('trials:dicom-show:EllipticalRoi')" class="btn-link" data-tool="EllipticalRoi"
@click="setToolActive($event, 'EllipticalRoi')">
<svg-icon icon-class="oval" style="font-size:20px;" />
</button>
<!-- 矩形测量 -->
<button :title="$t('trials:dicom-show:RectangleRoi')" class="btn-link" data-tool="RectangleRoi"
@click="setToolActive($event, 'RectangleRoi')">
<svg-icon icon-class="rectangle" style="font-size:20px;" />
</button>
<!-- 多边形标记 -->
<button :title="$t('trials:dicom-show:FreehandRoi')" class="btn-link" data-tool="FreehandRoi"
@click="setToolActive($event, 'FreehandRoi')">
<svg-icon icon-class="polygon" style="font-size:20px;" />
</button>
<!-- 十字线 -->
<button :title="$t('trials:dicom-show:Bidirectional')" class="btn-link" data-tool="Bidirectional"
@click="setToolActive($event, 'Bidirectional')">
<svg-icon icon-class="bidirection" style="font-size:20px;" />
</button>
<!-- 文字标注 -->
<button :title="$t('trials:dicom-show:ArrowAnnotate')" class="btn-link" data-tool="ArrowAnnotate"
@click="setToolActive($event, 'ArrowAnnotate')">
<svg-icon icon-class="label" style="font-size:20px;" />
</button>
<!-- 清除测量和标记 -->
<button :title="$t('trials:dicom-show:Eraser')" class="btn-link" data-tool="Eraser"
@click="setToolActive($event, 'Eraser')">
<svg-icon icon-class="clear" style="font-size:20px;" />
</button>
<!-- 截屏 -->
<button :title="$t('trials:dicom-show:image')" class="btn-link" @click="currentDicomCanvas.saveImage()">
<svg-icon icon-class="image" style="font-size:20px;" />
</button>
<!-- 标签 -->
<button :title="$t('trials:dicom-show:tags')" class="btn-link" @click="currentDicomCanvas.showTags()">
<svg-icon icon-class="dictionary" style="font-size:20px;" />
</button>
</div>
</div>
<div class="measureTool-wrapper">
<!-- 播放 -->
<div class="sideTool-title">{{ $t('trials:dicom-show:play') }}</div>
<div class="sideTool-wrapper">
<!-- 第一帧 -->
<button class="btn-link" :title="$t('trials:dicom-show:firstframe')"
@click="currentDicomCanvas.scrollPage(-9999)">
<svg-icon icon-class="firstframe" style="font-size:20px;" />
</button>
<!-- 显示上一张影像 -->
<button class="btn-link" :title="$t('trials:dicom-show:previousframe')"
@click="currentDicomCanvas.scrollPage(-1)">
<svg-icon icon-class="previousframe" style="font-size:20px;" />
</button>
<!-- 播放 -->
<button class="btn-link" :title="$t('trials:dicom-show:play')" @click="clipPlay">
<svg-icon :icon-class="currentDicomCanvas.toolState.clipPlaying ? 'stop' : 'play'"
style="font-size:20px;" />
</button>
<!-- 下一帧 -->
<button class="btn-link" :title="$t('trials:dicom-show:nextframe')" @click="currentDicomCanvas.scrollPage(1)">
<svg-icon icon-class="nextframe" style="font-size:20px;" />
</button>
<!-- 最后一帧 -->
<button class="btn-link" :title="$t('trials:dicom-show:lastframe')"
@click="currentDicomCanvas.scrollPage(9999)">
<svg-icon icon-class="lastframe" style="font-size:20px;" />
</button>
<select v-model="fps" class="sidetool-select" style="width:60px" @change="setDicomCanvasfps($event)">
<!-- 默认值 -->
<option :value="5">5</option>
<option :value="10">10</option>
<option :value="15">15</option>
<option :value="20">20</option>
<option :value="30">30</option>
</select>
</div>
</div>
<div class="measureTool-wrapper">
<!-- 颜色 -->
<div class="sideTool-title">{{ $t('trials:dicom-show:color') }}</div>
<div class="sideTool-wrapper">
<!-- 预设窗位值 -->
<label>{{ $t('trials:dicom-show:dicomCanvasWwwc') }}:</label>
<select v-model="wwwcList[currentDicomCanvasIndex]" class="sidetool-select" style="width:100px"
@change="setDicomCanvasWwwc($event)">
<!-- 默认值 -->
<option :value="-1">{{ $t('trials:dicom-show:default') }}</option>
<!-- 自定义 -->
<option :value="0">{{ $t('trials:dicom-show:custom') }}</option>
<!-- 区域窗宽 -->
<option :value="1" style="border-bottom:1px solid #fff;">{{ $t('trials:reading:button:wwwcRegion') }}
</option>
<option :value="2">CT Abdomen</option>
<option :value="3">CT Angio</option>
<option :value="4">CT Bone</option>
<option :value="5">CT Brain</option>
<option :value="6">CT Chest</option>
<option :value="7">CT Lungs</option>
</select>
</div>
<div class="sideTool-wrapper">
<!-- 伪彩色 -->
<label>{{ $t('trials:dicom-show:pseudocolor') }}:</label>
<select v-model="colorList[currentDicomCanvasIndex]" class="sidetool-select" style="width:90px"
@change="setColormap($event)">
<!-- 默认值 -->
<option value>{{ $t('trials:dicom-show:default') }}</option>
<option v-for="(item, index) in colormapsList" :key="index" :value="item.id">{{ item.name }}</option>
</select>
</div>
</div>
<!-- 患者信息 -->
<div class="measureTool-wrapper patient-form"
v-if="type === 'Study' && modality && ['PT、CT', 'CT、PT', 'PET-CT'].includes(modality)">
<div class="sideTool-title">{{ $t('trials:tab:patientData') }}</div>
<div class="sideTool-wrapper">
<el-form ref="patientForm" size="mini" :model="formData" :rules="rules" label-width="150" v-loading="formLoading">
<!-- 性别 -->
<el-form-item :label="$t('trials:ptData:label:patientSex')" prop="PatientSex">
<el-select v-model="formData.PatientSex" :placeholder="$t('common:ruleMessage:select')"
style="width: 100%" :disabled="!isEdit">
<el-option :label="$t('trials:patientSex:male')" value="M"></el-option>
<el-option :label="$t('trials:patientSex:female')" value="F"></el-option>
</el-select>
</el-form-item>
<!-- 体重kg 例如 70.5-->
<el-form-item :label="$t('trials:ptData:label:patientWeight')" prop="PatientWeight">
<el-input v-model.number="formData.PatientWeight" :placeholder="$t('trials:patientWeight:eg')"
style="width: 100%" :disabled="!isEdit"></el-input>
</el-form-item>
<!-- 总剂量Bq 例如 740000000-->
<el-form-item :label="$t('trials:ptData:label:totalDose')" prop="RadionuclideTotalDose">
<el-input v-model.number="formData.RadionuclideTotalDose" :placeholder="$t('trials:totalDose:eg')"
style="width: 100%" :disabled="!isEdit"></el-input>
</el-form-item>
<!-- 半衰期s 例如 21600-->
<el-form-item :label="$t('trials:ptData:label:halfLife')" prop="RadionuclideHalfLife">
<el-input v-model.number="formData.RadionuclideHalfLife" :placeholder="$t('trials:halfLife:eg')"
style="width: 100%" :disabled="!isEdit"></el-input>
</el-form-item>
<!-- 注射时间s Unix 秒 或 相对秒-->
<el-form-item :label="$t('trials:ptData:label:injectTime')" prop="RadiopharmaceuticalStartTime">
<el-input v-model.number="formData.RadiopharmaceuticalStartTime" :placeholder="$t('trials:injectTime:eg')"
style="width: 100%" @input="computeTimeRelation" :disabled="!isEdit"></el-input>
</el-form-item>
<!-- 成像时间s Unix 秒 或 相对秒-->
<el-form-item :label="$t('trials:ptData:label:acquisitionTime')" prop="AcquisitionTime">
<el-input v-model.number="formData.AcquisitionTime" :placeholder="$t('trials:injectTime:eg')"
style="width: 100%" @input="computeTimeRelation" :disabled="!isEdit"></el-input>
</el-form-item>
<!-- 时间一致性检查 -->
<!-- <el-form-item :label="$t('trials:ptData:label:timeCheck')">
<el-input v-model="formData.TimeCheck" disabled style="width: 100%"></el-input>
</el-form-item> -->
<!-- 提交 -->
<el-form-item style="margin-top: 20px;text-align: right;" v-if="isEdit">
<el-button type="primary" @click="submitForm" size="small">{{ $t('trials:ptData:button:submit')
}}</el-button>
</el-form-item>
</el-form>
</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" append-to-body>
<CustomWwwcForm @close="customWwc.visible = false" @setWwwc="setWwwc" />
</el-dialog>
</div>
</template>
<script>
import DicomCanvas from './DicomCanvas'
import CustomWwwcForm from './CustomWwwcForm'
import * as cornerstone from 'cornerstone-core'
import * as cornerstoneMath from 'cornerstone-math'
import * as cornerstoneTools from 'cornerstone-tools'
import Hammer from 'hammerjs'
// cornerstone.imageCache.setMaximumSizeBytes(0)
cornerstoneTools.external.cornerstone = cornerstone
cornerstoneTools.external.Hammer = Hammer
cornerstoneTools.external.cornerstoneMath = cornerstoneMath
console.log(cornerstoneTools, 'cornerstoneTools')
console.log(cornerstone, 'cornerstone')
import '@/utils/dialog'
import { studyMaskImage, studyUndoMaskImage } from "@/api/reading"
import {
getPatientInfo,
editPatientInfo
} from '@/api/trials'
import { setPTClinicalDataForInstance, clearPTClinicalDataCache } from '@/utils/ptClinicalDataCache'
export default {
name: 'DicomsViewer',
components: {
DicomCanvas,
CustomWwwcForm,
},
props: {
loading: {
type: Boolean,
default: false
},
Comparison: {
type: Boolean,
default: false
},
modality: {
type: String,
default: ''
}
},
watch: {
modality: {
immediate: true,
handler(v) {
if (v) {
if (this.type === 'Study' && ['PT、CT', 'CT、PT', 'PET-CT'].includes(v)) {
this.$nextTick(()=>{
this.getPatientInfo()
})
}
}
}
}
},
data() {
return {
hasAnonymous: false,
isAnonymous: false,
isComparison: false,
activeTool: '',
activeItem: 'dicomCanvas0',
layoutRow: 1,
layoutCol: 1,
currentDicomCanvasIndex: 0,
currentDicomCanvas: {
toolState: {
clipPlaying: false,
},
},
rowHeight: '100%',
sync: {
Wwwc: null,
},
colormapsList: [],
rotateList: [],
colorList: [],
wwwcList: [],
layout: null,
seriesList: [],
series: {},
customWwc: { visible: false, title: null },
fps: 15,
formData: {
Id: '',
PatientSex: '',
PatientWeight: null,
RadionuclideTotalDose: null,
RadionuclideHalfLife: null,
RadiopharmaceuticalStartTime: null,
AcquisitionTime: null,
TimeCheck: ''
},
rules: {
PatientSex: [
{ required: true, message: this.$t('common:ruleMessage:select'), trigger: 'change' }
],
PatientWeight: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ type: 'number', min: 0, message: this.$t('trials:ptData:ruleMessage:number1'), trigger: 'blur' }//数值必须大于0
],
RadionuclideTotalDose: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ type: 'number', min: 0, message: this.$t('trials:ptData:ruleMessage:number1'), trigger: 'blur' }//数值必须大于0
],
RadionuclideHalfLife: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ type: 'number', min: 0, message: this.$t('trials:ptData:ruleMessage:number1'), trigger: 'blur' }
],
RadiopharmaceuticalStartTime: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' }//请输入数字
],
AcquisitionTime: [
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
{ type: 'number', message: this.$t('trials:ptData:ruleMessage:number2'), trigger: 'blur' },//请输入数字
// 自定义校验:确保成像时间不早于注射时间
{ validator: this.validateTime, trigger: 'blur' }
]
},
formLoading: false,
type: '',
isEdit: 0
}
},
mounted() {
let type = this.$router.currentRoute.query.type ? this.$router.currentRoute.query.type : ''
this.hasAnonymous = type === 'Study'
this.customWwc = {
visible: false,
title: this.$t('DicomViewer:data:customWwc'),
}
this.rotateList[0] = '1'
this.colorList[0] = ''
this.wwwcList[0] = '-1'
this.colormapsList = cornerstone.colors.getColormapsList()
this.currentDicomCanvas = this.$refs['dicomCanvas0']
this.type = this.$route.query.type
this.isEdit = parseInt(this.$route.query.showDelete)
},
beforeDestroy() {
clearPTClinicalDataCache()
},
methods: {
comparison(f) {
this.isComparison = f
this.$emit("update:Comparison", f)
const elements = document.querySelectorAll('.dicom-item')
const scope = this
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
}
})
scope.activeTool = null
if (this.isComparison) {
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(obj => {
let { image } = obj
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
this.changeLayout('1x2')
let serie = {}
Object.keys(this.series).forEach(key => {
if (key !== 'instanceInfoList' && key !== 'imageIds') {
serie[key] = this.series[key]
}
})
let imageId = image.imageId
let newImageId = imageId.split("?")[0].split(".MaskDicom_")[0] + "?" + imageId.split("?")[1]
let info0 = {}, info1 = {}
Object.keys(instanceInfo).forEach(key => {
info0[key] = instanceInfo[key]
info1[key] = instanceInfo[key]
})
info0.ImageId = imageId
info1.ImageId = newImageId
console.log(info0)
console.log(info1)
let dicomCanvas0_info = Object.assign({
instanceInfoList: [
info0
],
imageIds: [imageId]
}, serie)
let dicomCanvas1_info = Object.assign({
instanceInfoList: [
info1
],
imageIds: [newImageId]
}, serie)
console.log(dicomCanvas0_info, 'dicomCanvas0_info')
console.log(dicomCanvas1_info, 'dicomCanvas0_info')
this.$refs[`dicomCanvas0`].loadImageStack(dicomCanvas0_info)
this.$refs[`dicomCanvas1`].loadImageStack(dicomCanvas1_info)
})
} else {
this.changeLayout('1x1')
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
},
recovery(isAll = false) {
if (this.isComparison) return false
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
let { image } = obj
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
if (!instanceInfo.IsMasked) return this.$confirm(this.$t("DicomViewer:anonymous:notMasked"))
let data = {
// SeriesId: this.series.seriesId,
instanceIdList: [instanceInfo.Id]
}
if (isAll) {
data.SeriesId = this.series.seriesId
delete data.instanceIdList
}
let res = await this.studyUndoMaskImage(data)
if (!res) return false
this.$emit("update:loading", true)
if (!isAll) {
let strs = image.imageId.split("?")
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
this.series.instanceInfoList.some(item => {
if (item.Id === instanceInfo.Id) {
item.ImageId = newImageId
item.IsMasked = false
}
return item.Id === instanceInfo.Id
})
let index = this.series.imageIds.findIndex(item => item === image.imageId)
this.series.imageIds.splice(index, 1, newImageId)
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
} else {
let arr = []
this.series.instanceInfoList.forEach(item => {
let strs = item.ImageId.split("?")
let info = res.find(i => item.Id === i.Id)
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
item.ImageId = newImageId
item.IsMasked = false
arr.push(newImageId)
})
this.series.imageIds = arr
console.log(this.series, 'this.series')
// this.loadImageStack(this.series)
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
this.$emit("update:loading", false)
this.$emit('loadStudy', false)
})
},
anonymousImage(isAll = false) {
if (this.isComparison) return false
this.$refs[`dicomCanvas0`].getNote_RectangleRoi().then(async obj => {
let { toolInfo, image } = obj
if (!toolInfo || toolInfo.data.length <= 0) return this.$confirm(this.$t("DicomViewer:anonymous:notMark"))
let instanceInfo = this.series.instanceInfoList.find(item => item.ImageId === image.imageId)
let data = {
// SeriesId: this.series.seriesId,
instanceIdList: [instanceInfo.Id],
MaskRegionList: []
}
if (isAll) {
data.SeriesId = this.series.seriesId
delete data.instanceIdList
}
toolInfo.data.forEach(item => {
let currentStart = item.handles.start
let currentEnd = item.handles.end
let start = {
x: currentStart.x > currentEnd.x ? Math.round(currentEnd.x) : Math.round(currentStart.x),
y: currentStart.y > currentEnd.y ? Math.round(currentEnd.y) : Math.round(currentStart.y),
}
let end = {
x: currentStart.x > currentEnd.x ? Math.round(currentStart.x) : Math.round(currentEnd.x),
y: currentStart.y > currentEnd.y ? Math.round(currentStart.y) : Math.round(currentEnd.y),
}
let width = end.x - start.x
let height = end.y - start.y
data.MaskRegionList.push({
X: start.x,
Y: start.y,
Width: width,
Height: height
})
})
let res = await this.studyMaskImage(data)
if (!res) return false
this.$emit("update:loading", true)
if (!isAll) {
let strs = image.imageId.split("?")
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${res[0].Path}?${strs[1]}`
this.series.instanceInfoList.some(item => {
if (item.Id === instanceInfo.Id) {
item.ImageId = newImageId
item.IsMasked = true
}
return item.Id === instanceInfo.Id
})
let index = this.series.imageIds.findIndex(item => item === image.imageId)
this.series.imageIds.splice(index, 1, newImageId)
await this.$refs[`dicomCanvas0`].reloadImage(newImageId)
} else {
let arr = []
this.series.instanceInfoList.forEach(item => {
let strs = item.ImageId.split("?")
let info = res.find(i => item.Id === i.Id)
let newImageId = `wadouri:${localStorage.getItem('location') !== 'USA' ? this.OSSclientConfig.basePath : this.OSSclientConfig.basePath}${info.Path}?${strs[1]}`
item.ImageId = newImageId
item.IsMasked = true
arr.push(newImageId)
})
this.series.imageIds = arr
console.log(this.series, 'this.series')
// this.loadImageStack(this.series)
this.$refs[`dicomCanvas0`].loadImageStack(this.series)
}
this.$emit("update:loading", false)
this.$emit('loadStudy', false)
})
},
openAnonymous() {
this.isAnonymous = !this.isAnonymous
if (!this.isAnonymous) {
const elements = document.querySelectorAll('.dicom-item')
const scope = this
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(scope.activeTool)
}
})
scope.activeTool = null
} else {
this.activateDicomCanvas(0)
this.changeLayout('1x1')
}
},
async studyMaskImage(data) {
try {
this.$emit("update:loading", true)
let res = await studyMaskImage(data)
this.$emit("update:loading", false)
if (res.IsSuccess) {
return res.Result.OkList
}
return false
} catch (err) {
console.log(err)
this.$emit("update:loading", false)
return false
}
},
async studyUndoMaskImage(data) {
try {
this.$emit("update:loading", true)
let res = await studyUndoMaskImage(data)
this.$emit("update:loading", false)
if (res.IsSuccess) {
return res.Result.OkList
}
return false
} catch (err) {
console.log(err)
this.$emit("update:loading", false)
return false
}
},
loadImageStack(dicomSeries) {
this.currentDicomCanvas.toolState.clipPlaying = false
this.$nextTick(() => {
this.series = Object.assign({}, dicomSeries)
this.seriesList = [this.series]
this.currentDicomCanvas.loadImageStack(this.series)
if (
this.formData.PatientWeight != null ||
this.formData.RadionuclideTotalDose != null ||
this.formData.RadionuclideHalfLife != null ||
this.formData.RadiopharmaceuticalStartTime != null ||
this.formData.AcquisitionTime != null
) {
this.cachePtClinicalDataToInstances()
}
})
},
loadOtherImageStack(seriesList) {
this.$nextTick(() => {
this.seriesList = seriesList
const elements = document.querySelectorAll('.dicom-item')
Array.from(elements).forEach((element, index) => {
const canvasIndex = element.getAttribute('data-index')
if (index < seriesList.length && element.style.display !== 'none') {
const series = Object.assign({}, seriesList[index])
this.$refs[`dicomCanvas${canvasIndex}`].loadImageStack(series)
}
})
if (
this.formData.PatientWeight != null ||
this.formData.RadionuclideTotalDose != null ||
this.formData.RadionuclideHalfLife != null ||
this.formData.RadiopharmaceuticalStartTime != null ||
this.formData.AcquisitionTime != null
) {
this.cachePtClinicalDataToInstances()
}
})
},
activateDicomCanvas(index) {
if (index !== this.currentDicomCanvasIndex) {
this.currentDicomCanvasIndex = index
this.currentDicomCanvas = this.$refs[`dicomCanvas${index}`]
this.currentDicomCanvas.tabIndex = 0
this.activeItem = `dicomCanvas${index}`
if (this.sync.ReferenceLines) {
if (this.sync['ReferenceLines']) {
const elements = this.sync['ReferenceLines'].getSourceElements()
if (elements.length > 0) {
this.$refs[`dicomCanvas${index}`].removeTarget(
this.sync['ReferenceLines']
)
this.sync['ReferenceLines'].addTarget(elements[0])
this.sync['ReferenceLines'].removeSource(elements[0])
this.$refs[`dicomCanvas${index}`].addSourceElement(
this.sync['ReferenceLines']
)
}
}
}
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'
}
}
},
changeLayout(event) {
const arr = event.target ? event.target.value.split('x') : event.split('x')
this.layoutRow = parseInt(arr[0])
this.layoutCol = parseInt(arr[1])
this.rowHeight = 100 / this.layoutRow + '%'
this.$forceUpdate()
this.$nextTick(() => {
const elements = document.querySelectorAll('.cornerstone-element')
Array.from(elements).forEach((element) => {
cornerstone.enable(element)
cornerstone.resize(element)
})
})
},
setFullScreen(e) {
if (this.layoutRow === 1 && this.layoutCol === 1) return
if (this.layout) {
e.currentTarget.classList.remove('dicom-item-fullscreen')
const arr = this.layout.split('x')
this.layoutRow = parseInt(arr[0])
this.layoutCol = parseInt(arr[1])
this.rowHeight = 100 / this.layoutRow + '%'
this.$forceUpdate()
this.$nextTick(() => {
const elements = document.querySelectorAll('.cornerstone-element')
Array.from(elements).forEach((element) => {
cornerstone.enable(element)
cornerstone.resize(element)
})
})
this.layout = null
} else {
this.layout = `${this.layoutRow}x${this.layoutCol}`
e.currentTarget.classList.add('dicom-item-fullscreen')
cornerstone.enable(e.currentTarget.children[0])
cornerstone.resize(e.currentTarget.children[0])
}
},
fillColor() {
const elements = document.querySelectorAll('.dicom-item')
const scope = this
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].fillColor()
}
})
},
setToolActive(e, toolName) {
const elements = document.querySelectorAll('.dicom-item')
if (e.currentTarget.classList.contains('activeTool')) {
e.currentTarget.classList.remove('activeTool')
const scope = this
scope.activeTool = null
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolPassive(toolName)
}
})
} else {
const toolButtons = document.querySelectorAll('[data-tool]')
Array.from(toolButtons).forEach((toolBtn) => {
toolBtn.classList.remove('activeTool')
})
e.currentTarget.classList.add('activeTool')
const scope = this
scope.activeTool = toolName
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
scope.$refs[`dicomCanvas${index}`].setToolActive(toolName)
}
})
}
},
setDicomCanvasWwwc(event) {
this.wwwcList[this.currentDicomCanvasIndex] = event.target.value
const type = parseInt(event.target.value)
if (type === -1) {
// 默认值
this.currentDicomCanvas.resetWwwc()
} else if (type === 0) {
// 自定义
this.customWwc.visible = true
} else if (type === 1) {
// 区域窗宽
this.currentDicomCanvas.setToolActive('WwwcRegion')
} else if (type === 2) {
this.currentDicomCanvas.setWwwc(400, 60)
} else if (type === 3) {
this.currentDicomCanvas.setWwwc(600, 300)
} else if (type === 4) {
this.currentDicomCanvas.setWwwc(1500, 300)
} else if (type === 5) {
this.currentDicomCanvas.setWwwc(80, 40)
} else if (type === 6) {
this.currentDicomCanvas.setWwwc(400, 40)
} else if (type === 7) {
this.currentDicomCanvas.setWwwc(1500, -400)
}
},
setWwwc(v) {
this.currentDicomCanvas.setWwwc(v.ww, v.wc)
this.customWwc.visible = false
},
toggleInvert() {
this.currentDicomCanvas.toggleInvert()
},
setDicomCanvasRotate(value) {
const type = parseInt(value)
if (type === 1) {
this.currentDicomCanvas.resetRotate()
} else if (type === 2) {
this.currentDicomCanvas.setRotate(true, false, 0, type)
} else if (type === 3) {
this.currentDicomCanvas.setRotate(false, true, 0, type)
} else if (type === 4) {
this.currentDicomCanvas.setRotate(false, false, -90, type)
} else if (type === 5) {
this.currentDicomCanvas.setRotate(false, false, 90, type)
}
},
setColormap(event) {
this.colorList[this.currentDicomCanvasIndex] = event.target.value
this.currentDicomCanvas.setColormap(event.target.value)
},
setDicomCanvasfps(event) {
this.currentDicomCanvas.setFps(event.target.value)
},
clipPlay() {
this.currentDicomCanvas.setFps(this.fps)
this.currentDicomCanvas.toggleClipPlay()
},
fitToType(e, type) {
const toolButtons = document.querySelectorAll('[data-tool]')
Array.from(toolButtons).forEach((toolBtn) => {
toolBtn.classList.remove('activeTool')
})
e.currentTarget.classList.add('activeTool')
if (type === 'fitToWindow') {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`].fitToWindow()
} else {
this.$refs[`dicomCanvas${this.currentDicomCanvasIndex}`].fitToImage()
}
},
setAnnotationSync(e) {
if (this.layoutRow * this.layoutCol === 1) {
return
}
this.resetSync('annotationSync')
let isActive = true
const toolBtn = e.currentTarget
if (toolBtn.classList.contains('activeTool')) {
toolBtn.classList.remove('activeTool')
isActive = false
} else {
toolBtn.classList.add('activeTool')
}
if (!this.sync.annotationSync) {
this.sync.annotationSync = new cornerstoneTools.Synchronizer(
'cornerstoneimagerendered',
cornerstoneTools.updateImageSynchronizer
)
}
const scope = this
const elements = document.querySelectorAll('.dicom-item')
Array.from(elements).forEach((element, index) => {
if (element.style.display !== 'none') {
if (isActive) {
if (index !== scope.currentDicomCanvasIndex) {
scope.$refs[`dicomCanvas${index}`].addTargetElement(
scope.sync['annotationSync']
)
} else {
scope.$refs[`dicomCanvas${index}`].addSourceElement(
scope.sync['annotationSync']
)
}
scope.$refs[`dicomCanvas${index}`].activeAnnotationSync(
scope.sync.annotationSync
)
} else {
scope.$refs[`dicomCanvas${index}`].disabledAnnotationSync(
scope.sync.annotationSync
)
}
}
})
if (!isActive) {
scope.sync.annotationSync = null
}
},
resetSync(prop) {
for (const key in this.sync) {
if (key !== prop) {
if (this.sync[prop]) {
this.sync[prop] = null
}
}
}
},
// 时间一致性校验
validateTime(rule, value, callback) {
const { RadiopharmaceuticalStartTime } = this.formData
if (value && RadiopharmaceuticalStartTime !== null && value < RadiopharmaceuticalStartTime) {
callback(new Error(this.$t('trials:ptData:ruleMessage:number3')))//成像时间不能早于注射时间
} else {
callback()
}
},
computeTimeRelation() {
const startTime = this.formData.RadiopharmaceuticalStartTime
const acquireTime = this.formData.AcquisitionTime
if (!startTime || !acquireTime) {
this.formData.TimeCheck = ''
return
}
if (startTime <= acquireTime) {
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val1') //注射时间 ≤ 成像时间
} else {
this.formData.TimeCheck = this.$t('trials:ptData:timeCheck:val2') //注射时间 > 成像时间
}
},
async getPatientInfo() {
try {
this.formLoading = true
let studyId = this.$route.query.studyId
let res = await getPatientInfo({studyId: studyId})
this.formData = {
Id: res.Result.Id || '',
PatientSex: res.Result.PatientSex || '',
PatientWeight: parseFloat(res.Result.PatientWeight) || null,
RadionuclideTotalDose: parseFloat(res.Result.RadionuclideTotalDose) || null,
RadionuclideHalfLife: parseFloat(res.Result.RadionuclideHalfLife) || null,
RadiopharmaceuticalStartTime: parseFloat(res.Result.RadiopharmaceuticalStartTime) || '',
AcquisitionTime: parseFloat(res.Result.AcquisitionTime) || '',
TimeCheck: ''
}
this.computeTimeRelation()
// 缓存 PT 临床数据:用于 2D SUV 计算时优先使用接口/人工录入值
this.cachePtClinicalDataToInstances()
this.formLoading = false
} catch(e) {
this.formLoading = false
console.log(e)
}
},
cachePtClinicalDataToInstances() {
const clinicalData = {
PatientSex: this.formData.PatientSex,
PatientWeight: this.formData.PatientWeight,
RadionuclideTotalDose: this.formData.RadionuclideTotalDose,
RadionuclideHalfLife: this.formData.RadionuclideHalfLife,
RadiopharmaceuticalStartTime: this.formData.RadiopharmaceuticalStartTime,
AcquisitionTime: this.formData.AcquisitionTime
}
const seriesList = Array.isArray(this.seriesList) ? this.seriesList : []
seriesList.forEach(series => {
const instanceInfoList = series?.instanceInfoList
if (Array.isArray(instanceInfoList) && instanceInfoList.length > 0) {
instanceInfoList.forEach(instance => {
if (instance && instance.Id != null) {
setPTClinicalDataForInstance(instance.Id, clinicalData)
}
})
return
}
const imageIds = series?.imageIds
if (Array.isArray(imageIds) && imageIds.length > 0) {
imageIds.forEach(imageId => {
const instanceId = this.getInstanceIdFromImageId(imageId)
if (instanceId) {
setPTClinicalDataForInstance(instanceId, clinicalData)
}
})
}
})
},
getInstanceIdFromImageId(imageId) {
try {
const qIndex = String(imageId).indexOf('?')
if (qIndex === -1) return null
const params = new URLSearchParams(String(imageId).slice(qIndex + 1))
const instanceId = params.get('instanceId')
return instanceId ? String(instanceId).trim() : null
} catch (e) {
return null
}
},
refreshDicomAfterClinicalDataChanged() {
// 患者信息保存后,强制刷新画布与标注统计,确保 SUV 等数据显示使用最新的 PT 临床数据口径
const toolTypes = [
'Probe',
'RectangleRoi',
'EllipticalRoi',
'FreehandRoi',
'Bidirectional',
'Length',
'ArrowAnnotate',
'Angle',
'CobbAngle'
]
const elements = document.querySelectorAll('.dicom-item')
Array.from(elements).forEach((wrapper) => {
const index = wrapper.getAttribute('data-index')
const canvasComp = index !== null ? this.$refs[`dicomCanvas${index}`] : null
const element = canvasComp?.$refs?.canvas
if (!element) return
toolTypes.forEach((toolType) => {
const toolState = cornerstoneTools.getToolState(element, toolType)
if (toolState && Array.isArray(toolState.data)) {
toolState.data.forEach((d) => {
if (d && typeof d === 'object') {
d.invalidated = true
}
})
}
})
cornerstone.updateImage(element, true)
})
},
async submitForm() {
try {
let valid = await this.$refs.patientForm.validate()
if (!valid) return
this.formLoading = true
let res = await editPatientInfo(this.formData)
this.formLoading = false
if (res.IsSuccess) {
this.$message.success(this.$t('common:message:savedSuccessfully'))
this.cachePtClinicalDataToInstances()
this.refreshDicomAfterClinicalDataChanged()
}
} catch (e) {
this.formLoading = false
console.log(e)
}
}
}
}
</script>
<style>
.dicom-wrapper {
display: flex;
height: 100%;
}
.dicom-wrapper .case-dialog-class {
position: fixed;
left: 25%;
pointer-events: auto;
display: block;
overflow: auto;
}
.dicom-wrapper .case-dialog-div {
pointer-events: none;
}
.dicom-wrapper .case-dialog-class .el-dialog__body {
max-height: 300px;
overflow-y: auto;
}
.dicom-wrapper .el-dialog__header {
padding: 15px;
}
.dicom-wrapper .el-dialog__body {
padding: 10px 20px;
}
.dicom-viewer {
display: flex;
flex-direction: column;
flex: 1;
position: relative;
}
.Anonymous {
position: absolute;
border-radius: 5px;
bottom: 30px;
left: 5%;
right: 5%;
width: 90%;
height: 60px;
padding: 0 10px;
background-color: rgba(255, 255, 255, .2);
display: flex;
align-items: center;
justify-content: space-between;
z-index: 9999;
.btn {
width: 15%;
text-align: center;
height: 40px;
line-height: 30px;
border-radius: 15px;
background-color: rgba(255, 255, 255, .3);
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255, 255, 255, .7);
&:hover {
background-color: rgba(255, 255, 255, .5);
}
}
.activeBtn {
background-color: rgba(255, 255, 255, .5);
}
.isNoted {
cursor: not-allowed;
}
}
.Anonymous .btn {
width: 15%;
text-align: center;
height: 40px;
line-height: 30px;
border-radius: 15px;
background-color: rgba(255, 255, 255, .3);
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255, 255, 255, .7);
}
.Anonymous .btn:hover {
background-color: rgba(255, 255, 255, .5);
}
.Anonymous .activeBtn {
background-color: rgba(255, 255, 255, .5);
}
.btnBox {
display: inline-block;
width: 80px;
text-align: center;
height: 30px;
line-height: 20px;
border-radius: 15px;
background-color: rgba(255, 255, 255, .3);
cursor: pointer;
padding: 5px 10px;
border: 1px solid rgba(255, 255, 255, .7);
margin: 5px;
}
.dicom-wrapper .dicom-row {
display: flex;
flex-direction: row;
flex: 1;
width: 100%;
}
.dicom-wrapper .dicom-item {
position: relative;
width: 0;
flex: 1;
flex-shrink: 1;
box-sizing: border-box;
padding: 5px;
border: 1px solid #c8c8c8;
}
.dicom-wrapper .activeItem {
border: 2px solid chocolate;
}
.dicom-item-fullscreen {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.dicom-wrapper ::-webkit-scrollbar {
width: 7px;
height: 7px;
}
.dicom-wrapper ::-webkit-scrollbar-thumb {
border-radius: 10px;
background: gray;
}
.dicom-wrapper .dicom-tools {
/* display: flex;
flex-direction: column; */
width: 300px;
height: 100%;
background-color: #323232;
margin: 0;
padding: 0;
margin-left: 2px;
/* border: 1px solid blueviolet; */
color: #d0d0d0;
font-size: 13px;
overflow-y: auto;
}
.dicom-wrapper .measure-wrapper {
display: flex;
flex-direction: column;
flex: 1;
overflow: hidden;
}
.measure-wrapper .measure-list {
flex: 1;
overflow-y: auto;
}
.measure-list-header {
padding: 2px 0px;
border-bottom: 1px solid gray;
}
.measure-wrapper ul {
margin: 0;
padding: 0 5px;
list-style: none;
}
.measure-wrapper ul li {
height: 20px;
display: flex;
justify-content: space-between;
margin-bottom: 5px;
text-align: center;
}
.measure-wrapper select {
height: 20px;
background-color: rgba(0, 0, 0, 0);
/* color: #323232; */
border-radius: 4px;
font-size: 13px;
color: #606626;
}
.measure-wrapper select>option {
color: #323232;
}
/* .measure-wrapper select {
height: 20px;
background-color: rgba(0, 0, 0, 0);
color: #d0d0d0;
border-radius: 4px;
}
.measure-wrapper select > option {
background-color: #323232;
} */
.dicom-canvas {
position: relative;
width: 100%;
height: 100%;
border: 1px solid #333333;
}
.dicom-canvas.active {
border: 1px solid #337ab7;
}
.sideTool-title {
padding: 5px 8px;
background-color: #525252;
color: #bebdbd;
font-size: 14px;
margin: 4px;
}
.sideTool-wrapper {
border-bottom: 1px solid gray;
margin: 0px 4px;
padding: 4px;
font-size: 12px;
}
.sideTool-wrapper .btn {
font-size: 12px;
}
.sidetool-select {
height: 30px;
background-color: rgba(0, 0, 0, 0);
color: #d0d0d0;
border-radius: 4px;
}
.sidetool-select>option {
background-color: #323232;
}
.sideTool-wrapper button.btn-link {
height: 40px;
padding: 8px !important;
border: 1px solid rgba(37, 37, 37, 1);
margin: 1px 1px;
}
.sideTool-wrapper .btn-link {
display: inline-block;
height: 40px;
padding: 8px !important;
border: 1px solid rgba(37, 37, 37, 1);
margin: 1px 1px;
}
.dicom-wrapper .btn-group {
position: relative;
display: inline-block;
height: 30px;
padding: 6px 3px;
vertical-align: middle;
margin: 1px 1px;
border-radius: 3px;
font-size: 12px;
font-weight: 500;
color: silver;
line-height: 20px !important;
background: rgba(50, 50, 50, 1);
border: 1px solid rgba(37, 37, 37, 1);
min-height: 30px;
}
.dicom-wrapper .btn-group .btn-left {
position: relative;
float: left;
padding: 1px !important;
margin-left: 0;
border-bottom-right-radius: 0;
border-top-right-radius: 0;
}
.dicom-wrapper .activeTool {
background: #16477b90 !important;
border: none;
}
.dicom-wrapper .btn-link {
color: #cccccc;
background-color: #ffffff00;
cursor: pointer;
}
.dicom-wrapper .btn-submit {
cursor: pointer;
/* background-color: #eeeeee; */
background: #eeeeee;
border: 1px solid #dcdfe6;
border-radius: 4px;
color: #606266;
font-size: 13px;
}
/* .dicom-wrapper .btn-link:hover,
.dicom-wrapper .btn-link:focus,
.dicom-wrapper .btn-link:active {
border-color: transparent;
background-color: transparent;
} */
.dicom-wrapper .iconHover:hover {
color: red;
}
.dicom-wrapper .dropdown {
position: relative;
display: inline-block;
}
.dicom-wrapper .dropdown-content {
display: none;
position: absolute;
left: -20px;
top: 40px;
color: #d0d0d0;
background-color: #323232;
min-width: 100px;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
border: 1px solid #4e4e4e;
padding: 5px;
}
.dicom-wrapper .dropdown:hover .dropdown-content {
display: block;
}
.dicom-wrapper .dropdown-content div {
height: 25px;
line-height: 25px;
cursor: point;
}
.dicom-wrapper .dropdown-content div:hover {
background-color: #16477b90;
}
.patient-form .el-form-item {
display: flex;
align-items: center;
margin-bottom: 15px;
}
.patient-form .el-form-item__label {
color: #d0d0d0;
flex: 0 0 150px;
text-align: left;
}
.patient-form .el-form-item__content {
flex: 1;
margin-left: 0;
}
.patient-form .el-input.is-disabled .el-input__inner {
background-color: #424244;
}
.patient-form .el-input .el-input__inner {
background-color: #323232;
color: #d0d0d0;
}
</style>