1608 lines
60 KiB
Vue
1608 lines
60 KiB
Vue
<template>
|
|
<div class="none-dicom-viewer">
|
|
<!-- tools -->
|
|
<div class="tools-wrapper">
|
|
<div class="tools-left">
|
|
<!-- 布局 -->
|
|
<div class="tool-item" :title="$t('trials:reading:button:layout')">
|
|
<el-dropdown @command="handleCommand">
|
|
<span class="el-dropdown-link">
|
|
<svg-icon icon-class="layout" class="svg-icon" /><i class="el-icon-arrow-down el-icon--right" />
|
|
</span>
|
|
<el-dropdown-menu slot="dropdown">
|
|
<el-dropdown-item command="1*1">1*1</el-dropdown-item>
|
|
<el-dropdown-item command="1*2">1*2</el-dropdown-item>
|
|
<el-dropdown-item command="2*2">2*2</el-dropdown-item>
|
|
</el-dropdown-menu>
|
|
</el-dropdown>
|
|
</div>
|
|
<!-- 缩放 -->
|
|
<div :class="['tool-item', activeTool === 'Zoom' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:reading:button:zoom')" @click.prevent="setToolActive('Zoom')">
|
|
<svg-icon icon-class="magnifier" class="svg-icon" />
|
|
</div>
|
|
<!-- 移动 -->
|
|
<div :class="['tool-item', activeTool === 'Pan' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:reading:button:move')" @click.prevent="setToolActive('Pan')">
|
|
<svg-icon icon-class="move" class="svg-icon" />
|
|
</div>
|
|
<!-- 旋转 -->
|
|
<div :class="['tool-item', activeTool === 'PlanarRotate' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:reading:button:rotate')" @click.prevent="setToolActive('PlanarRotate')">
|
|
<svg-icon icon-class="rotate" class="svg-icon" />
|
|
</div>
|
|
<div v-for="tool in tools" :key="tool.toolName"
|
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
|
|
:style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
|
|
:title="tool.disabledReason ? tool.disabledReason : $t(`${tool.i18nKey}`)"
|
|
@click.prevent="setAnnotateToolActive(tool.toolName)">
|
|
<svg-icon :icon-class="tool.icon" class="svg-icon" />
|
|
</div>
|
|
<!-- <div
|
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'SplineROITool' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:reading:button:SplineROITool')"
|
|
@click.prevent="setAnnotateToolActive('SplineROITool')"
|
|
>
|
|
<svg-icon icon-class="polygon" class="svg-icon" />
|
|
</div> -->
|
|
|
|
<div
|
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Eraser' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:dicom-show:Eraser')" @click.prevent="setAnnotateToolActive('Eraser')">
|
|
<svg-icon icon-class="clear" class="svg-icon" />
|
|
</div>
|
|
<!--比例尺-->
|
|
<div
|
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Lengthscale' ? 'tool-item-active' : '']"
|
|
:title="$t('trials:nondicom-show:scale')" @click.prevent="setAnnotateToolActive('Lengthscale')">
|
|
<svg-icon icon-class="lengthscale" class="svg-icon" />
|
|
</div>
|
|
<!-- 截图 -->
|
|
<!-- <div
|
|
class="tool-item"
|
|
:title="$t('trials:reading:button:screenShot')"
|
|
@click.prevent="saveImage"
|
|
>
|
|
<svg-icon icon-class="image" class="svg-icon" />
|
|
</div> -->
|
|
<!-- 重置 -->
|
|
<div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport">
|
|
<svg-icon icon-class="refresh" class="svg-icon" />
|
|
</div>
|
|
<!-- 更多 -->
|
|
<div v-if="criterionType === 0" :title="$t('trials:reading:button:more')"
|
|
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" @click.stop="showPanel($event)"
|
|
@mouseleave="toolMouseout">
|
|
<div class="dropdown">
|
|
<div class="icon" data-tool="more">
|
|
<svg-icon icon-class="more" class="svg-icon" />
|
|
<i class="el-icon-arrow-down" style="color:#fff;" />
|
|
</div>
|
|
<div class="dropdown-content">
|
|
<ul v-if="readingTaskState < 2" style="width:100px;">
|
|
<li v-for="i in customizeStandardsNoneDicom" :key="i.toolName" style="text-align:left;">
|
|
<a href="#" @click.prevent="setAnnotateToolActive(i.toolName)">
|
|
<svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;" />
|
|
{{ $t(i.i18nKey) }}
|
|
</a>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="tool-item" :title="$t('trials:reading:button:upload')"
|
|
v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']">
|
|
<div class="tool-wrapper">
|
|
<div class="icon" @click.prevent="openUploadImage('upload')">
|
|
<i class="el-icon-upload2 svg-icon" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div v-if="trialCriterion.ImageDownloadEnum > 0" v-hasPermi="[
|
|
'role:ir',
|
|
'role:mim',
|
|
'role:mc',
|
|
'role:pm',
|
|
'role:apm',
|
|
'role:ea',
|
|
'role:qa',
|
|
]" class="tool-item" :title="$t('trials:reading:button:download')">
|
|
<div class="tool-wrapper">
|
|
<div class="icon" @click.prevent="openUploadImage('download')">
|
|
<i class="el-icon-download svg-icon" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<el-button type="text" @click="previewConfig">{{ $t('trials:reading:button:customCfg') }}</el-button>
|
|
</div>
|
|
</div>
|
|
<!-- viewports -->
|
|
<div class="viewports-wrapper">
|
|
<div class="grid-container" :style="gridStyle">
|
|
<div v-for="(v, index) in viewportInfos" v-show="index < cells.length" :key="index" :style="cellStyle"
|
|
:class="['grid-cell', index === activeCanvasIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
|
|
@dblclick="toggleFullScreen($event, index)" @click="activeCanvas(index)"
|
|
@mouseup="sliderMouseup($event, index)" @mousemove="sliderMousemove($event, index)"
|
|
@mouseleave="sliderMouseleave($event, index)">
|
|
<div v-show="imageType.includes(v.fileType)" :ref="`canvas-${index}`" class="content">
|
|
<div class="left-top-text">
|
|
<div v-if="v.taskInfo.IsExistsClinicalData" class="cd-info"
|
|
:title="$t('trials:reading:button:clinicalData')">
|
|
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
|
|
@click.stop="viewCD(v.taskInfo.VisitTaskId)" />
|
|
</div>
|
|
<h2 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo" class="subject-info">
|
|
{{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
|
|
</h2>
|
|
<!-- <div v-if="v.currentFileName">{{ v.currentFileName }}</div> -->
|
|
</div>
|
|
<div v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo" class="top-center-tool">
|
|
<div class="toggle-visit-container">
|
|
<div class="arrw_icon"
|
|
:style="{ cursor: v.taskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
|
|
@click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, -1, v.index)"
|
|
@dblclick.stop="preventDefault($event)">
|
|
<i class="el-icon-caret-left" />
|
|
</div>
|
|
<div class="arrow_text">
|
|
{{ v.taskInfo.TaskBlindName }}
|
|
</div>
|
|
<div class="arrw_icon"
|
|
:style="{ cursor: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
|
|
@click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, 1, v.index)"
|
|
@dblclick.stop="preventDefault($event)">
|
|
<i class="el-icon-caret-right" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div :ref="`sliderBox-${index}`" class="right-slider-box" @click.stop="clickSlider($event, index)">
|
|
<div :style="{ top: v.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
|
|
@mousedown.stop="sliderMousedown($event, index)" />
|
|
</div>
|
|
</div>
|
|
<div v-show="v.fileType === 'application/pdf' && fullScreenIndex === null" class="content flex_col">
|
|
<div class="content-top" style="height: 50px;">
|
|
<div class="left-top-text">
|
|
<div v-if="v.taskInfo.IsExistsClinicalData" class="cd-info"
|
|
:title="$t('trials:reading:button:clinicalData')">
|
|
<svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
|
|
@click.stop="viewCD(v.taskInfo.VisitTaskId)" />
|
|
</div>
|
|
<h2 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo" class="subject-info">
|
|
{{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
|
|
</h2>
|
|
<!-- <div v-if="v.currentFileName">{{ v.currentFileName }}</div> -->
|
|
</div>
|
|
<div v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo" class="top-center-tool">
|
|
<div class="toggle-visit-container">
|
|
<div class="arrw_icon"
|
|
:style="{ cursor: v.taskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
|
|
@click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, -1, v.index)"
|
|
@dblclick.stop="preventDefault($event)">
|
|
<i class="el-icon-caret-left" />
|
|
</div>
|
|
<div class="arrow_text">
|
|
{{ v.taskInfo.TaskBlindName }}
|
|
</div>
|
|
<div class="arrw_icon"
|
|
:style="{ cursor: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
|
|
@click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, 1, v.index)"
|
|
@dblclick.stop="preventDefault($event)">
|
|
<i class="el-icon-caret-right" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="content-main" style="flex: 1;">
|
|
<iframe v-if="v.currentFilePath" :ref="`iframe-${index}`"
|
|
:src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${v.currentFilePath}?index=${index}`"
|
|
width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<el-dialog :title="$t('trials:noneDicom:message:msg2')" :visible.sync="dialogVisible" :close-on-click-modal="false"
|
|
:close-on-press-escape="false" :show-close="false" width="400px">
|
|
<el-form ref="lengthForm" :model="form" :rules="rules">
|
|
<el-form-item label="" prop="length">
|
|
<el-input v-model="form.length" type="number">
|
|
<template slot="append">mm</template>
|
|
</el-input>
|
|
</el-form-item>
|
|
</el-form>
|
|
<span slot="footer" class="dialog-footer">
|
|
<el-button type="primary" @click="saveForm">{{ $t('common:button:save') }}</el-button>
|
|
</span>
|
|
</el-dialog>
|
|
|
|
<el-dialog v-if="personalConfigDialog.visible" :visible.sync="personalConfigDialog.visible"
|
|
:close-on-click-modal="false" :title="personalConfigDialog.title" width="600px">
|
|
<Others />
|
|
</el-dialog>
|
|
<upload-dicom-and-nonedicom v-if="uploadImageVisible" :subject-id="uploadSubjectId"
|
|
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :visible.sync="uploadImageVisible"
|
|
:visit-task-id="taskId" :is-reading-task-view-in-order="isReadingTaskViewInOrder" />
|
|
<download-dicom-and-nonedicom v-if="downloadImageVisible" :subject-id="uploadSubjectId"
|
|
:subject-code="uploadSubjectCode" :criterion="uploadTrialCriterion" :task-id="taskId"
|
|
:visible.sync="downloadImageVisible" />
|
|
</div>
|
|
</template>
|
|
<script>
|
|
import { addNoneDicomMark, deleteTrialFileType, getCriterionReadingInfo } from '@/api/trials'
|
|
import {
|
|
RenderingEngine,
|
|
Enums,
|
|
imageLoader,
|
|
metaData,
|
|
getRenderingEngine,
|
|
eventTarget,
|
|
utilities as csUtils
|
|
// getEnabledElementByIds
|
|
} from '@cornerstonejs/core'
|
|
|
|
import * as cornerstoneTools from '@cornerstonejs/tools'
|
|
import initLibraries from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/initLibraries'
|
|
import hardcodedMetaDataProvider from './../js/hardcodedMetaDataProvider'
|
|
import registerWebImageLoader from './../js/registerWebImageLoader'
|
|
import { mapGetters } from 'vuex'
|
|
import store from '@/store'
|
|
import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others'
|
|
const { ViewportType } = Enums
|
|
const renderingEngineId = 'myRenderingEngine'
|
|
import LengthscaleTool from "../tools/LengthscaleTool"
|
|
import { getCustomizeStandardsNoneDicomTools, config } from '@/views/trials/trials-panel/reading/dicoms3D/components/toolConfig'
|
|
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
|
|
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
|
|
const {
|
|
ToolGroupManager,
|
|
Enums: csToolsEnums,
|
|
StackScrollTool,
|
|
PanTool,
|
|
ZoomTool,
|
|
PlanarRotateTool,
|
|
ArrowAnnotateTool,
|
|
RectangleROITool,
|
|
PlanarFreehandROITool,
|
|
SplineROITool,
|
|
EraserTool,
|
|
LengthTool,
|
|
EllipticalROITool,
|
|
CircleROITool,
|
|
AngleTool
|
|
// cursors
|
|
} = cornerstoneTools
|
|
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
|
export default {
|
|
name: 'ImageViewer',
|
|
components: {
|
|
Others,
|
|
downloadDicomAndNonedicom,
|
|
uploadDicomAndNonedicom,
|
|
},
|
|
props: {
|
|
relatedStudyInfo: {
|
|
type: Object,
|
|
default() {
|
|
return {}
|
|
}
|
|
},
|
|
psArr: {
|
|
type: Array,
|
|
default() {
|
|
return []
|
|
}
|
|
}
|
|
},
|
|
data() {
|
|
return {
|
|
rows: 1,
|
|
cols: 1,
|
|
fullScreenIndex: null,
|
|
imageIds: [],
|
|
activeCanvasIndex: 0,
|
|
activeCanvasFileType: '',
|
|
layout: '1*2',
|
|
cellsMax: 4,
|
|
viewportInfos: [],
|
|
taskInfo: null,
|
|
activeTool: '',
|
|
readingTaskState: 2,
|
|
renderHistoryAnnotationTaskIds: [],
|
|
imageType: ['image/jpeg', 'image/jpg', 'image/bmp', 'image/png'],
|
|
digitPlaces: 2,
|
|
dialogVisible: false,
|
|
personalConfigDialog: { visible: false, title: this.$t('trials:reading:button:customCfg') }, // 个性化配置
|
|
form: {
|
|
length: null,
|
|
annotationObj: {}
|
|
},
|
|
rules: {
|
|
length: [
|
|
{ required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
|
|
{ pattern: /^\d+$/, message: this.$t('trials:noneDicom:message:msg3'), trigger: ['blur', 'change'] }
|
|
]
|
|
},
|
|
|
|
customizeStandardsNoneDicom: [],
|
|
tools: [],
|
|
criterionType: null,
|
|
|
|
|
|
// 上传
|
|
downloadImageVisible: false,
|
|
uploadImageVisible: false,
|
|
uploadSubjectId: null,
|
|
uploadSubjectCode: null,
|
|
uploadTrialCriterion: {},
|
|
uploadStatus: 'upload',
|
|
taskId: '',
|
|
isReadingTaskViewInOrder: null,
|
|
trialCriterion: {}
|
|
}
|
|
},
|
|
computed: {
|
|
gridStyle() {
|
|
return {
|
|
display: 'grid',
|
|
gridTemplateRows: `repeat(${this.rows}, 1fr)`,
|
|
gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
|
|
height: '100%',
|
|
width: '100%'
|
|
}
|
|
},
|
|
cellStyle() {
|
|
return {
|
|
border: '1px dashed #ccc',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'center'
|
|
}
|
|
},
|
|
cells() {
|
|
return Array(this.rows * this.cols).fill(0)
|
|
},
|
|
...mapGetters(['lastViewportTaskId', 'currentTaskState'])
|
|
},
|
|
watch: {
|
|
relatedStudyInfo: {
|
|
immediate: true,
|
|
handler(obj) {
|
|
if (!obj || Object.keys(obj).length === 0) return
|
|
this.updateViewportInfos(0, obj)
|
|
}
|
|
},
|
|
currentTaskState: {
|
|
immediate: true,
|
|
handler(state) {
|
|
if (state === 2) {
|
|
this.readingTaskState = 2
|
|
// 设置标记锁定
|
|
const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
|
|
annotations.map(annotation => {
|
|
cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
|
|
})
|
|
this.setToolsPassive()
|
|
}
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
|
|
this.readingTaskState = this.taskInfo.ReadingTaskState
|
|
this.criterionType = this.taskInfo.CriterionType
|
|
if (this.criterionType === 0) {
|
|
this.tools = getCustomizeStandardsNoneDicomTools(this.taskInfo.ReadingToolList)
|
|
const toolNames = this.tools.map(i => i.toolName)
|
|
this.customizeStandardsNoneDicom = config.customizeStandardsNoneDicom.filter(item => !toolNames.includes(item.toolName))
|
|
} else {
|
|
this.tools = config.customizeStandardsNoneDicom
|
|
}
|
|
if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
|
|
this.rows = 1
|
|
this.cols = 2
|
|
this.activeCanvasIndex = 1
|
|
}
|
|
this.viewportInfos = Array.from({ length: this.cellsMax }, (_, index) => ({
|
|
index: index,
|
|
taskInfo: '',
|
|
studyId: '',
|
|
currentImageIdIndex: 0,
|
|
viewportId: `canvas-${index}`,
|
|
fileType: '',
|
|
currentFileName: '',
|
|
currentFilePath: '',
|
|
imageIds: [],
|
|
oldB: null,
|
|
oldM: null,
|
|
isMove: false,
|
|
height: 0
|
|
}))
|
|
const digitPlaces = Number(localStorage.getItem('digitPlaces'))
|
|
this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
|
|
this.initLoader()
|
|
window.addEventListener('message', this.handleIframeMessage)
|
|
this.getTrialCriterion()
|
|
},
|
|
beforeDestroy() {
|
|
window.removeEventListener('message', this.handleIframeMessage)
|
|
},
|
|
methods: {
|
|
getTrialCriterion() {
|
|
getCriterionReadingInfo({
|
|
TrialId: this.$route.query.trialId,
|
|
TrialReadingCriterionId: this.$route.query.TrialReadingCriterionId
|
|
})
|
|
.then((res) => {
|
|
this.trialCriterion = res.Result
|
|
})
|
|
.catch(() => { })
|
|
},
|
|
openUploadImage(status) {
|
|
this.taskId = this.taskInfo.VisitTaskId
|
|
this.uploadSubjectCode = localStorage.getItem("subjectCode")
|
|
this.uploadSubjectId = localStorage.getItem("subjectId")
|
|
this.uploadTrialCriterion = this.trialCriterion
|
|
this.uploadStatus = status
|
|
this[`${status}ImageVisible`] = true
|
|
},
|
|
showPanel(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'block'
|
|
},
|
|
toolMouseout(e) {
|
|
e.currentTarget.firstChild.lastChild.style.display = 'none'
|
|
},
|
|
// 初始化加载器
|
|
async initLoader() {
|
|
registerWebImageLoader(imageLoader)
|
|
await initLibraries()
|
|
|
|
let renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (!renderingEngine) {
|
|
renderingEngine = new RenderingEngine(renderingEngineId)
|
|
}
|
|
const resizeObserver = new ResizeObserver(() => {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (renderingEngine) {
|
|
renderingEngine.resize(true, false)
|
|
}
|
|
})
|
|
const element1 = this.$refs['canvas-0'][0]
|
|
const element2 = this.$refs['canvas-1'][0]
|
|
const element3 = this.$refs['canvas-2'][0]
|
|
const element4 = this.$refs['canvas-3'][0]
|
|
const elements = [
|
|
element1,
|
|
element2,
|
|
element3,
|
|
element4
|
|
]
|
|
elements.forEach((element, i) => {
|
|
element.oncontextmenu = (e) => e.preventDefault()
|
|
resizeObserver.observe(element)
|
|
element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
|
|
})
|
|
const viewportInputArray = [
|
|
{
|
|
viewportId: 'canvas-0',
|
|
type: ViewportType.STACK,
|
|
element: element1
|
|
},
|
|
{
|
|
viewportId: 'canvas-1',
|
|
type: ViewportType.STACK,
|
|
element: element2
|
|
},
|
|
{
|
|
viewportId: 'canvas-2',
|
|
type: ViewportType.STACK,
|
|
element: element3
|
|
},
|
|
{
|
|
viewportId: 'canvas-3',
|
|
type: ViewportType.STACK,
|
|
element: element4
|
|
}
|
|
]
|
|
const viewportIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
|
|
renderingEngine.setViewports(viewportInputArray)
|
|
this.addAnnotationListeners()
|
|
cornerstoneTools.addTool(StackScrollTool)
|
|
cornerstoneTools.addTool(PanTool)
|
|
cornerstoneTools.addTool(ZoomTool)
|
|
cornerstoneTools.addTool(PlanarRotateTool)
|
|
cornerstoneTools.addTool(ArrowAnnotateTool)
|
|
cornerstoneTools.addTool(RectangleROITool)
|
|
cornerstoneTools.addTool(EllipticalROITool)
|
|
cornerstoneTools.addTool(CircleROITool)
|
|
cornerstoneTools.addTool(AngleTool)
|
|
cornerstoneTools.addTool(PlanarFreehandROITool)
|
|
cornerstoneTools.addTool(SplineROITool)
|
|
cornerstoneTools.addTool(EraserTool)
|
|
cornerstoneTools.addTool(LengthTool)
|
|
cornerstoneTools.addTool(LengthscaleTool)
|
|
|
|
viewportIds.forEach((viewportId, i) => {
|
|
const toolGroupId = `canvas-${i}`
|
|
const toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
|
|
toolGroup.addViewport(viewportId, renderingEngineId)
|
|
toolGroup.addTool(StackScrollTool.toolName)
|
|
toolGroup.addTool(PanTool.toolName)
|
|
toolGroup.addTool(ZoomTool.toolName)
|
|
toolGroup.addTool(PlanarRotateTool.toolName)
|
|
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
|
arrowHeadStyle: 'standard',
|
|
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
|
return doneChangingTextCallback(await this.customPrompt())
|
|
},
|
|
getTextCallback: async (doneChangingTextCallback) => {
|
|
return doneChangingTextCallback(await this.customPrompt())
|
|
}
|
|
})
|
|
toolGroup.addTool(RectangleROITool.toolName, {
|
|
cachedStats: false,
|
|
getTextLines: this.getRectangleROIToolTextLines
|
|
})
|
|
toolGroup.addTool(EllipticalROITool.toolName, {
|
|
cachedStats: false,
|
|
getTextLines: this.getEllipticalROIToolTextLines
|
|
})
|
|
toolGroup.addTool(CircleROITool.toolName, {
|
|
cachedStats: false,
|
|
getTextLines: this.getCircleROIToolTextLines
|
|
})
|
|
toolGroup.addTool(AngleTool.toolName)
|
|
toolGroup.addTool(PlanarFreehandROITool.toolName, {
|
|
allowOpenContours: false,
|
|
cachedStats: false,
|
|
getTextLines: this.getPlanarFreehandROIToolTextLines
|
|
})
|
|
// const splineConfig = toolGroup.getToolConfiguration(
|
|
// splineToolName,
|
|
// 'spline'
|
|
// )
|
|
toolGroup.addTool(SplineROITool.toolName)
|
|
|
|
toolGroup.addTool(EraserTool.toolName)
|
|
toolGroup.addTool(LengthTool.toolName, {
|
|
getTextLines: this.getLengthToolTextLines,
|
|
cachedStats: false
|
|
})
|
|
toolGroup.addTool(LengthscaleTool.toolName, {
|
|
getTextLines: this.getLengthscaleToolTextLines,
|
|
cachedStats: false
|
|
})
|
|
|
|
toolGroup.setToolActive(StackScrollTool.toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
|
})
|
|
toolGroup.setToolPassive(PanTool.toolName)
|
|
toolGroup.setToolPassive(ZoomTool.toolName)
|
|
toolGroup.setToolPassive(PlanarRotateTool.toolName)
|
|
if (this.readingTaskState < 2) {
|
|
toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
|
|
toolGroup.setToolPassive(RectangleROITool.toolName)
|
|
toolGroup.setToolPassive(EllipticalROITool.toolName)
|
|
toolGroup.setToolPassive(CircleROITool.toolName)
|
|
toolGroup.setToolPassive(AngleTool.toolName)
|
|
toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
|
|
toolGroup.setToolPassive(SplineROITool.toolName)
|
|
toolGroup.setToolPassive(LengthTool.toolName)
|
|
toolGroup.setToolPassive(LengthscaleTool.toolName)
|
|
} else {
|
|
toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
|
|
toolGroup.setToolEnabled(RectangleROITool.toolName)
|
|
toolGroup.setToolEnabled(EllipticalROITool.toolName)
|
|
toolGroup.setToolEnabled(CircleROITool.toolName)
|
|
toolGroup.setToolEnabled(AngleTool.toolName)
|
|
toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
|
|
toolGroup.setToolEnabled(SplineROITool.toolName)
|
|
toolGroup.setToolEnabled(LengthTool.toolName)
|
|
toolGroup.setToolEnabled(LengthscaleTool.toolName)
|
|
}
|
|
toolGroup.setToolPassive(EraserTool.toolName)
|
|
})
|
|
},
|
|
|
|
// 加载图片回调
|
|
stackNewImage(e) {
|
|
const { detail } = e
|
|
const i = this.viewportInfos.findIndex(i => i.viewportId === detail.viewportId)
|
|
if (i === -1) return
|
|
this.viewportInfos[i].currentImageIdIndex = detail.imageIdIndex
|
|
const obj = this.viewportInfos[i].fileList[detail.imageIdIndex]
|
|
if (!obj) return
|
|
this.viewportInfos[i].currentFileName = obj.FileName
|
|
this.viewportInfos[i].height = (this.viewportInfos[i].currentImageIdIndex) * 100 / (this.viewportInfos[i].imageIds.length - 1)
|
|
const path = detail.imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, path: path })
|
|
this.renderHistoryAnnotations(this.viewportInfos[i].taskInfo)
|
|
},
|
|
renderHistoryAnnotations(obj) {
|
|
if (this.renderHistoryAnnotationTaskIds.includes(obj.VisitTaskId)) return
|
|
this.renderHistoryAnnotationTaskIds.push(obj.VisitTaskId)
|
|
// let arr = []
|
|
obj.Annotations.map(i => {
|
|
const annotation = i.MeasureData
|
|
annotation.annotationId = i.Id
|
|
cornerstoneTools.annotation.state.addAnnotation(annotation)
|
|
if (obj.ReadingTaskState === 2) {
|
|
cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
|
|
}
|
|
})
|
|
},
|
|
// 渲染图片
|
|
async renderImage(imageIds, canvasIndex, sliceIndex) {
|
|
metaData.addProvider((type, imageId) => hardcodedMetaDataProvider(type, imageId, imageIds), 10000)
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${canvasIndex}`)
|
|
await viewport.setStack(imageIds)
|
|
viewport.setImageIdIndex(sliceIndex)
|
|
viewport.render()
|
|
// this.updateViewportInfos()
|
|
},
|
|
setActiveCanvasImages(obj) {
|
|
console.log('setActiveCanvasImages')
|
|
if (!obj || Object.keys(obj).length === 0) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (obj.studyId === this.viewportInfos[i].studyId && this.imageType.includes(this.viewportInfos[i].fileType) && this.imageType.includes(obj.fileInfo.FileType)) {
|
|
const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
|
|
this.sliceIndex(fileIndex)
|
|
} else {
|
|
if (!this.imageType.includes(obj.fileInfo.FileType)) {
|
|
this.fullScreenIndex = null
|
|
}
|
|
this.updateViewportInfos(this.activeCanvasIndex, obj)
|
|
}
|
|
if (this.activeCanvasIndex === this.cells.length - 1) {
|
|
store.dispatch('noneDicomReview/setLastViewportTaskId', obj.visitTaskInfo.VisitTaskId)
|
|
}
|
|
},
|
|
// 激活视图
|
|
activeCanvas(index) {
|
|
if (this.activeCanvasIndex === index) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
this.activeCanvasIndex = index
|
|
if (index === this.cells.length - 1) {
|
|
store.dispatch('noneDicomReview/setLastViewportTaskId', this.viewportInfos[i].taskInfo.VisitTaskId)
|
|
}
|
|
this.$emit('toggleTask', this.viewportInfos[i].taskInfo)
|
|
this.setToolsPassive()
|
|
},
|
|
// 更新视图信息
|
|
updateViewportInfos(index, obj) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
|
|
this.viewportInfos[i].taskInfo = obj.visitTaskInfo
|
|
|
|
this.viewportInfos[i].currentFileName = obj.fileInfo.FileName
|
|
this.viewportInfos[i].studyId = obj.studyId
|
|
this.viewportInfos[i].fileType = obj.fileInfo.FileType
|
|
if (this.imageType.includes(obj.fileInfo.FileType)) {
|
|
const arr = obj.fileList.filter(i => this.imageType.includes(i.FileType))
|
|
this.viewportInfos[i].fileList = arr
|
|
const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
|
|
this.viewportInfos[i].currentImageIdIndex = fileIndex
|
|
const imageIds = []
|
|
for (let i = 0; i < arr.length; i++) {
|
|
const path = arr[i].Path
|
|
imageIds.push(`web:${this.OSSclientConfig.basePath}${path}`)
|
|
}
|
|
this.viewportInfos[i].imageIds = imageIds
|
|
if (imageIds.length > 0) {
|
|
this.renderImage(imageIds, index, fileIndex)
|
|
}
|
|
this.$nextTick(() => {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
if (renderingEngine) {
|
|
renderingEngine.resize(true, false)
|
|
}
|
|
})
|
|
} else {
|
|
this.viewportInfos[i].currentFilePath = obj.fileInfo.Path
|
|
}
|
|
},
|
|
// 切换图片
|
|
sliceIndex(index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (index < 0 || index >= this.viewportInfos[i].imageIds.length) return
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
viewport.setImageIdIndex(index)
|
|
viewport.render()
|
|
},
|
|
// 更改视图布局
|
|
handleCommand(command) {
|
|
this.fullScreenIndex = null
|
|
this.layout = command
|
|
this.rows = parseInt(command.split('*')[0])
|
|
this.cols = parseInt(command.split('*')[1])
|
|
if (this.rows === 1 && this.cols === 1) {
|
|
this.$nextTick(() => {
|
|
this.activeCanvas(0)
|
|
})
|
|
}
|
|
// 有序阅片 1*1 显示当前图片 1*2 显示基线*当前图片 2*2 显示当前图片
|
|
// const obj = this.viewportInfos.find(i => i.index === this.activeCanvasIndex)
|
|
// if (obj && this.rows === 1 && this.cols === 1) {
|
|
// this.viewportInfos = this.viewportInfos.map((v, i) => {
|
|
// if (i === 0) {
|
|
// v.taskInfo = obj.taskInfo
|
|
// v.currentImageIdIndex === obj.currentImageIdIndex
|
|
// v.currentFileName === obj.currentFileName
|
|
// v.imageIds === obj.imageIds
|
|
// } else {
|
|
// v.taskInfo = ''
|
|
// v.currentImageIdIndex === 0
|
|
// v.currentFileName === ''
|
|
// v.imageIds === []
|
|
// }
|
|
// return v
|
|
// })
|
|
// this.activeCanvasIndex = 0
|
|
// } else if (obj && this.rows === 1 && this.cols === 2 && this.taskInfo.IsReadingTaskViewInOrder === 1) {
|
|
// this.viewportInfos = this.viewportInfos.map((v, i) => {
|
|
// if (i === 0) {
|
|
// v.taskInfo = this.relatedStudyInfo.visitTaskInfo
|
|
// v.currentImageIdIndex === this.relatedStudyInfo.fileIndex
|
|
// v.currentFileName === this.relatedStudyInfo.fileInfo.FileName
|
|
// const imageIds = []
|
|
// for (let i = 0; i < this.relatedStudyInfo.fileList.length; i++) {
|
|
// const path = this.relatedStudyInfo.fileList[i].Path
|
|
// imageIds.push(`web:${this.OSSclientConfig.basePath}${path}`)
|
|
// }
|
|
// v.imageIds === imageIds
|
|
// } else if (i === 1) {
|
|
// v.taskInfo = obj.taskInfo
|
|
// v.currentImageIdIndex === obj.currentImageIdIndex
|
|
// v.currentFileName === obj.currentFileName
|
|
// v.imageIds === obj.imageIds
|
|
// } else {
|
|
// v.taskInfo = ''
|
|
// v.currentImageIdIndex === 0
|
|
// v.currentFileName === ''
|
|
// v.imageIds === []
|
|
// }
|
|
// return v
|
|
// })
|
|
// this.activeCanvasIndex = 1
|
|
// } else if (obj && this.rows === 1 && this.cols === 2 && this.taskInfo.IsReadingTaskViewInOrder !== 1) {
|
|
// this.viewportInfos = this.viewportInfos.map((v, i) => {
|
|
// if (i === 0 || i === 1) {
|
|
// v.taskInfo = obj.taskInfo
|
|
// v.currentImageIdIndex === obj.currentImageIdIndex
|
|
// v.currentFileName === obj.currentFileName
|
|
// v.imageIds === obj.imageIds
|
|
// } else {
|
|
// v.taskInfo = ''
|
|
// v.currentImageIdIndex === 0
|
|
// v.currentFileName === ''
|
|
// v.imageIds === []
|
|
// }
|
|
// return v
|
|
// })
|
|
// this.activeCanvasIndex = 1
|
|
// } else if (obj && (this.rows === 2 && this.cols === 2)) {
|
|
// this.viewportInfos = this.viewportInfos.map(v => {
|
|
// v.taskInfo = obj.taskInfo
|
|
// v.currentImageIdIndex === obj.currentImageIdIndex
|
|
// v.currentFileName === obj.currentFileName
|
|
// v.imageIds === obj.imageIds
|
|
// return v
|
|
// })
|
|
// this.activeCanvasIndex = 3
|
|
// }
|
|
// this.$nextTick(() => {
|
|
// this.viewportInfos.forEach(v => {
|
|
// if (v.imageIds.length > 0) {
|
|
// this.renderImage(v.imageIds, v.index, v.currentImageIdIndex)
|
|
// }
|
|
// })
|
|
// })
|
|
},
|
|
// 切换全屏
|
|
toggleFullScreen(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
if (!this.viewportInfos[i].currentFileName) return
|
|
if (this.imageType.includes(this.viewportInfos[i].fileType)) {
|
|
this.fullScreenIndex = this.fullScreenIndex === index ? null : index
|
|
this.activeCanvasIndex = index
|
|
}
|
|
},
|
|
// 切换任务
|
|
toggleTask(evt, visitTaskNum, i, index) {
|
|
this.activeCanvas(index)
|
|
const num = visitTaskNum + i
|
|
if (num >= 0 && num <= this.taskInfo.VisitNum) {
|
|
this.$emit('toggleTaskByViewer', num)
|
|
}
|
|
|
|
evt.stopImmediatePropagation()
|
|
evt.stopPropagation()
|
|
evt.preventDefault()
|
|
},
|
|
// 激活工具
|
|
setToolActive(toolName) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
const toolGroupId = `canvas-${this.viewportInfos[i].index}`
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
if (this.activeTool === toolName) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
this.activeTool = ''
|
|
} else {
|
|
if (this.activeTool) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
}
|
|
toolGroup.setToolActive(toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
|
})
|
|
this.activeTool = toolName
|
|
}
|
|
},
|
|
// 激活标注工具
|
|
setAnnotateToolActive(toolName) {
|
|
if (this.readingTaskState === 2) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (this.viewportInfos[i].taskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
|
|
const toolGroupId = `canvas-${this.viewportInfos[i].index}`
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
if (this.activeTool === toolName) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
this.activeTool = ''
|
|
} else {
|
|
if (this.activeTool) {
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
}
|
|
if (toolName === 'Lengthscale') {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
|
|
const imageId = viewport.csImage.imageId
|
|
const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
|
|
const idx = annotations.findIndex(i => i.metadata.referencedImageId === imageId && i.metadata.toolName === 'Lengthscale')
|
|
if (idx > -1) {
|
|
this.activeTool = ''
|
|
// 当前图像已存在比例尺!
|
|
this.$message.warning(this.$t('trials:noneDicom:message:msg4'))
|
|
return
|
|
}
|
|
}
|
|
toolGroup.setToolActive(toolName, {
|
|
bindings: [{ mouseButton: MouseBindings.Primary }]
|
|
})
|
|
this.activeTool = toolName
|
|
}
|
|
}
|
|
},
|
|
setToolsPassive() {
|
|
if (!this.activeTool) return
|
|
const toolGroupIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
|
|
toolGroupIds.forEach(toolGroupId => {
|
|
const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
|
|
toolGroup.setToolPassive(this.activeTool)
|
|
})
|
|
this.activeTool = ''
|
|
// const enabledElement = getEnabledElementByIds(
|
|
// `canvas-${this.activeCanvasIndex}`,
|
|
// renderingEngineId
|
|
// )
|
|
// cursors.setCursorForElement(enabledElement.viewport.element, 'default')
|
|
},
|
|
addAnnotationListeners() {
|
|
const debouncedCallback = this.debounce((evt) => {
|
|
this.annotationModifiedListener(evt)
|
|
}, 100)
|
|
eventTarget.addEventListener(
|
|
toolsEvents.ANNOTATION_MODIFIED,
|
|
(evt) => {
|
|
debouncedCallback(evt)
|
|
}
|
|
)
|
|
eventTarget.addEventListener(
|
|
toolsEvents.ANNOTATION_COMPLETED,
|
|
this.annotationCompletedListener
|
|
)
|
|
eventTarget.addEventListener(
|
|
toolsEvents.ANNOTATION_REMOVED,
|
|
this.annotationRemovedListener
|
|
)
|
|
},
|
|
async annotationRemovedListener(e) {
|
|
if (this.readingTaskState === 2) return
|
|
const { annotation } = e.detail
|
|
if (!annotation) return
|
|
if (annotation.annotationId) {
|
|
await deleteTrialFileType(annotation.annotationId)
|
|
} else {
|
|
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
|
|
}
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
|
|
viewport.render()
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
const imageId = annotation.metadata.referencedImageId
|
|
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const fileList = this.viewportInfos[i].fileList
|
|
const fileIndex = fileList.findIndex(f => f.Path === path)
|
|
if (annotation.metadata.toolName === 'Lengthscale') {
|
|
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
|
|
}
|
|
},
|
|
async annotationModifiedListener(e) {
|
|
console.log('Modified')
|
|
if (this.readingTaskState === 2) return
|
|
const { annotation } = e.detail
|
|
if (!annotation) return
|
|
if (!annotation.annotationId) return
|
|
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (this.viewportInfos[i].taskInfo.VisitTaskId !== this.taskInfo.VisitTaskId) return
|
|
const imageId = annotation.metadata.referencedImageId
|
|
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const fileList = this.viewportInfos[i].fileList
|
|
const fileIndex = fileList.findIndex(f => f.Path === path)
|
|
if (fileIndex === -1) return
|
|
if (annotation.metadata.toolName === 'Lengthscale') {
|
|
const value = annotation.data.l
|
|
if (value) {
|
|
const cachedStats = Object.keys(annotation.data.cachedStats)
|
|
const ps = value / annotation.data.cachedStats[cachedStats[0]].length
|
|
annotation.data.ps = ps
|
|
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: ps })
|
|
}
|
|
this.setToolsPassive()
|
|
}
|
|
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
|
|
const params = {
|
|
id: annotation.annotationId,
|
|
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
|
|
studyId: this.viewportInfos[i].studyId,
|
|
noneDicomFileId: fileList[fileIndex].Id,
|
|
path: fileList[fileIndex].Path,
|
|
measureData: JSON.stringify(annotation)
|
|
}
|
|
await addNoneDicomMark(params)
|
|
// 保存成功
|
|
// this.$message.success(this.$t('common:message:savedSuccessfully'))
|
|
},
|
|
async annotationCompletedListener(e) {
|
|
console.log('Completed')
|
|
if (this.readingTaskState === 2) return
|
|
const { annotation } = e.detail
|
|
if (!annotation) return
|
|
if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
|
|
const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
|
|
if (i === -1) return
|
|
if (this.viewportInfos[i].taskInfo.VisitTaskId !== this.taskInfo.VisitTaskId) return
|
|
const imageId = annotation.metadata.referencedImageId
|
|
const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const fileList = this.viewportInfos[i].fileList
|
|
const fileIndex = fileList.findIndex(f => f.Path === path)
|
|
if (fileIndex === -1) return
|
|
if (annotation.metadata.toolName === 'Lengthscale') {
|
|
this.form.annotationObj = {
|
|
id: '',
|
|
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
|
|
studyId: this.viewportInfos[i].studyId,
|
|
noneDicomFileId: fileList[fileIndex].Id,
|
|
path: fileList[fileIndex].Path,
|
|
annotation,
|
|
fileList,
|
|
fileIndex
|
|
}
|
|
this.form.length = null
|
|
this.dialogVisible = true
|
|
this.setToolsPassive()
|
|
return
|
|
}
|
|
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
|
|
const params = {
|
|
id: '',
|
|
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
|
|
studyId: this.viewportInfos[i].studyId,
|
|
noneDicomFileId: fileList[fileIndex].Id,
|
|
path: fileList[fileIndex].Path,
|
|
measureData: JSON.stringify(annotation)
|
|
}
|
|
const res = await addNoneDicomMark(params)
|
|
annotation.annotationId = res.Result
|
|
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
|
|
viewport.render()
|
|
// 保存成功
|
|
// this.$message.success(this.$t('common:message:savedSuccessfully'))
|
|
},
|
|
async saveForm() {
|
|
const validate = await this.$refs.lengthForm.validate()
|
|
if (!validate) return
|
|
const value = this.form.length
|
|
const annotation = this.form.annotationObj.annotation
|
|
const fileList = this.form.annotationObj.fileList
|
|
const fileIndex = this.form.annotationObj.fileIndex
|
|
if (value) {
|
|
annotation.data.l = parseFloat(value)
|
|
const cachedStats = Object.keys(annotation.data.cachedStats)
|
|
const ps = parseFloat(value) / annotation.data.cachedStats[cachedStats[0]].length
|
|
annotation.data.ps = ps
|
|
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: ps })
|
|
} else {
|
|
cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
|
|
return
|
|
}
|
|
if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
|
|
const params = {
|
|
id: '',
|
|
visitTaskId: this.form.annotationObj.visitTaskId,
|
|
studyId: this.form.annotationObj.studyId,
|
|
noneDicomFileId: this.form.annotationObj.noneDicomFileId,
|
|
path: this.form.annotationObj.path,
|
|
measureData: JSON.stringify(annotation)
|
|
}
|
|
const res = await addNoneDicomMark(params)
|
|
annotation.annotationId = res.Result
|
|
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
|
|
viewport.render()
|
|
this.dialogVisible = false
|
|
},
|
|
getLengthscaleToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const { length, unit } = cachedVolumeStats
|
|
if (length === undefined || length === null || isNaN(length)) {
|
|
return
|
|
}
|
|
if (data.l === undefined || data.l === null || isNaN(data.l)) {
|
|
return
|
|
}
|
|
const textLines = []
|
|
textLines.push(`P: ${parseFloat(length).toFixed(this.digitPlaces)} ${unit}`)
|
|
if (data.l) {
|
|
textLines.push(`L: ${parseFloat(data.l).toFixed(this.digitPlaces)} mm`)
|
|
textLines.push(`PS: ${parseFloat(data.l / length).toFixed(3)} mm/px`)
|
|
}
|
|
return textLines
|
|
},
|
|
// 直线工具注释
|
|
getLengthToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const { length, unit } = cachedVolumeStats
|
|
if (length === undefined || length === null || isNaN(length)) {
|
|
return
|
|
}
|
|
let ps = null
|
|
const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const i = this.psArr.findIndex(i => i.Path === path)
|
|
if (i > -1 && this.psArr[i].PS) {
|
|
ps = parseFloat(this.psArr[i].PS).toFixed(3)
|
|
}
|
|
const textLines = []
|
|
if (ps) {
|
|
textLines.push(`${this.reRound(csUtils.roundNumber(length * ps), this.digitPlaces)} mm`)
|
|
} else {
|
|
textLines.push(`${this.reRound(csUtils.roundNumber(length), this.digitPlaces)} ${unit}`)
|
|
}
|
|
return textLines
|
|
},
|
|
getPlanarFreehandROIToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const {
|
|
area,
|
|
mean,
|
|
stdDev,
|
|
// length,
|
|
perimeter,
|
|
max,
|
|
isEmptyArea,
|
|
unit,
|
|
areaUnit,
|
|
modalityUnit
|
|
} = cachedVolumeStats || {}
|
|
|
|
const textLines = []
|
|
let ps = null
|
|
const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const i = this.psArr.findIndex(i => i.Path === path)
|
|
if (i > -1 && this.psArr[i].PS) {
|
|
ps = parseFloat(this.psArr[i].PS).toFixed(3)
|
|
}
|
|
if (area) {
|
|
const areaLine = isEmptyArea
|
|
? `Area: Oblique not supported`
|
|
: `Area: ${ps ? this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces) : this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${ps ? 'mm' + '\xb2' : areaUnit}`
|
|
textLines.push(areaLine)
|
|
}
|
|
if (mean) {
|
|
textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
|
|
}
|
|
|
|
if (max) {
|
|
textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
|
|
}
|
|
|
|
if (stdDev) {
|
|
textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
|
|
}
|
|
|
|
if (perimeter) {
|
|
if (ps) {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
|
|
} else {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} ${unit}`)
|
|
}
|
|
}
|
|
|
|
// if (length) {
|
|
// // No need to show length prefix as there is just the single value
|
|
// textLines.push(`${csUtils.roundNumber(length)} ${unit}`);
|
|
// }
|
|
|
|
return textLines
|
|
},
|
|
getRectangleROIToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const points = data.handles.points
|
|
const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats
|
|
|
|
if (mean === undefined) {
|
|
return
|
|
}
|
|
|
|
const textLines = []
|
|
let ps = null
|
|
const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const i = this.psArr.findIndex(i => i.Path === path)
|
|
if (i > -1 && this.psArr[i].PS) {
|
|
ps = parseFloat(this.psArr[i].PS).toFixed(3)
|
|
}
|
|
if (ps) {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
|
|
} else {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
|
|
}
|
|
textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
|
|
if (Array.isArray(points) && points.length === 4) {
|
|
let perimeter = 2 * Math.abs(points[0][0] - points[1][0]) + 2 * Math.abs(points[1][1] - points[2][1])
|
|
if (perimeter) {
|
|
if (ps) {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
|
|
} else {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} px`)
|
|
}
|
|
}
|
|
}
|
|
return textLines
|
|
},
|
|
// 椭圆工具注释信息
|
|
getEllipticalROIToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats
|
|
|
|
if (mean === undefined) {
|
|
return
|
|
}
|
|
|
|
const textLines = []
|
|
let ps = null
|
|
const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const i = this.psArr.findIndex(i => i.Path === path)
|
|
if (i > -1 && this.psArr[i].PS) {
|
|
ps = parseFloat(this.psArr[i].PS).toFixed(3)
|
|
}
|
|
if (ps) {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
|
|
} else {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
|
|
}
|
|
textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
|
|
return textLines
|
|
},
|
|
// 圆形工具注释信息
|
|
getCircleROIToolTextLines(data, targetId) {
|
|
const cachedVolumeStats = data.cachedStats[targetId]
|
|
const { area, mean, max, stdDev, perimeter, areaUnit, modalityUnit } = cachedVolumeStats
|
|
|
|
if (mean === undefined) {
|
|
return
|
|
}
|
|
|
|
const textLines = []
|
|
let ps = null
|
|
const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
|
|
const i = this.psArr.findIndex(i => i.Path === path)
|
|
if (i > -1 && this.psArr[i].PS) {
|
|
ps = parseFloat(this.psArr[i].PS).toFixed(3)
|
|
}
|
|
if (ps) {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
|
|
} else {
|
|
textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
|
|
}
|
|
textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
|
|
textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
|
|
if (perimeter) {
|
|
if (ps) {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
|
|
} else {
|
|
textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} px`)
|
|
}
|
|
}
|
|
return textLines
|
|
},
|
|
reRound(result, finalPrecision) {
|
|
if (typeof result === 'string' && result.includes(', ')) {
|
|
const numStrs = result.split(', ')
|
|
const processed = numStrs.map(str => this.processSingle(str, finalPrecision))
|
|
return processed.join(', ')
|
|
}
|
|
return this.processSingle(result, finalPrecision)
|
|
},
|
|
processSingle(str, precision) {
|
|
const num = parseFloat(str)
|
|
if (isNaN(num)) return 'NaN'
|
|
|
|
// 保留原极小值处理逻辑
|
|
if (Math.abs(num) < 0.0001) return str
|
|
const factor = 10 ** precision
|
|
return (Math.round(num * factor + 0.0000001) / factor).toFixed(precision)
|
|
},
|
|
debounce(callback, delay) {
|
|
let timerId
|
|
return function () {
|
|
clearTimeout(timerId)
|
|
timerId = setTimeout(() => {
|
|
callback.apply(this, arguments)
|
|
}, delay)
|
|
}
|
|
},
|
|
// 重置视图
|
|
resetViewport() {
|
|
this.setToolsPassive()
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewportId = `canvas-${this.activeCanvasIndex}`
|
|
const viewport = (renderingEngine.getViewport(viewportId))
|
|
viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
|
|
renderingEngine.render()
|
|
},
|
|
// 箭头工具输入标记名称自定义弹窗
|
|
async customPrompt() {
|
|
try {
|
|
// 请输入标记名称
|
|
const { value } = await this.$prompt(this.$t('trials:noneDicom:message:msg1'))
|
|
return value
|
|
} catch {
|
|
return null
|
|
}
|
|
},
|
|
// 滚动条
|
|
clickSlider(e, index) {
|
|
const height = e.offsetY * 100 / this.$refs[`sliderBox-${index}`][0].clientHeight
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
this.viewportInfos[i].height = height
|
|
let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
|
|
sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
viewport.setImageIdIndex(sliceIdx)
|
|
viewport.render()
|
|
// this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, imageIndex: sliceIdx })
|
|
},
|
|
sliderMouseup(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
this.viewportInfos[i].isMove = false
|
|
},
|
|
sliderMousemove(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
if (!this.viewportInfos[i].isMove) return
|
|
const delta = this.viewportInfos[i].oldB - (this.viewportInfos[i].oldM - e.clientY)
|
|
const boxHeight = this.$refs[`sliderBox-${index}`][0].clientHeight
|
|
if (delta < 0) return
|
|
if (delta > boxHeight) return
|
|
const height = delta * 100 / boxHeight
|
|
let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
|
|
sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
|
|
this.viewportInfos[i].height = height
|
|
// if (this.viewportInfos[i].currentImageIdIndex !== i) {
|
|
const renderingEngine = getRenderingEngine(renderingEngineId)
|
|
const viewport = renderingEngine.getViewport(
|
|
this.viewportInfos[i].viewportId
|
|
)
|
|
viewport.setImageIdIndex(sliceIdx)
|
|
viewport.render()
|
|
// }
|
|
// this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, imageIndex: sliceIdx })
|
|
},
|
|
sliderMouseleave(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
|
|
if (!this.viewportInfos[i].isMove) return
|
|
this.viewportInfos[i].isMove = false
|
|
},
|
|
sliderMousedown(e, index) {
|
|
const i = this.viewportInfos.findIndex(i => i.index === index)
|
|
if (i === -1) return
|
|
const boxHeight = this.$refs[`sliderBox-${index}`][0].clientHeight
|
|
this.viewportInfos[i].oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
|
|
this.viewportInfos[i].oldM = e.clientY
|
|
this.viewportInfos[i].isMove = true
|
|
e.stopImmediatePropagation()
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
},
|
|
handleIframeMessage(event) {
|
|
if (event.data.type === 'pdf-clicked') {
|
|
const baseUrl = event.data.data.baseUrl
|
|
const urlParams = new URL(baseUrl)
|
|
const index = parseInt(urlParams.search.split('=')[1])
|
|
this.activeCanvas(index)
|
|
}
|
|
},
|
|
preventDefault(e) {
|
|
e.stopImmediatePropagation()
|
|
e.stopPropagation()
|
|
e.preventDefault()
|
|
},
|
|
// 查看临床数据
|
|
viewCD(id) {
|
|
this.$emit('previewCD', id)
|
|
},
|
|
previewConfig() {
|
|
this.personalConfigDialog.visible = true
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style lang="scss" scoped>
|
|
.content {
|
|
cursor: default !important;
|
|
}
|
|
|
|
.dropdown {
|
|
position: relative;
|
|
display: inline-block;
|
|
|
|
.text {
|
|
text-align: center;
|
|
}
|
|
}
|
|
|
|
.dropdown-content {
|
|
display: none;
|
|
position: absolute;
|
|
background-color: #383838;
|
|
color: #fff;
|
|
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
|
|
z-index: 9999;
|
|
font-size: 12px;
|
|
|
|
ul {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
text-align: center;
|
|
|
|
li {
|
|
a {
|
|
display: block;
|
|
padding: 5px;
|
|
}
|
|
}
|
|
}
|
|
|
|
ul li a:hover {
|
|
background-color: #727272;
|
|
}
|
|
}
|
|
|
|
.none-dicom-viewer {
|
|
display: flex;
|
|
flex-direction: column;
|
|
width: 100%;
|
|
height: 100%;
|
|
user-select: none;
|
|
|
|
.tools-wrapper {
|
|
height: 50px;
|
|
display: flex;
|
|
align-items: center;
|
|
border-bottom: 1px solid #727272;
|
|
color: #ddd;
|
|
padding: 0 5px;
|
|
|
|
.tools-left {
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: flex-start;
|
|
align-items: center;
|
|
}
|
|
|
|
.tool-item {
|
|
padding: 5px;
|
|
margin: 0 5px;
|
|
border: 1px solid #333;
|
|
font-size: 20px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.tool-item-active {
|
|
background-color: #607d8b;
|
|
}
|
|
|
|
.tool-disabled {
|
|
cursor: not-allowed;
|
|
}
|
|
}
|
|
|
|
.viewports-wrapper {
|
|
flex: 1;
|
|
|
|
.grid-container {
|
|
display: grid;
|
|
height: 100%;
|
|
width: 100%;
|
|
position: relative;
|
|
}
|
|
|
|
.grid-cell {
|
|
border: 1px dashed #ccc;
|
|
;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.cell_active {
|
|
border-color: #fafa00 !important;
|
|
}
|
|
|
|
.cell-full-screen {
|
|
grid-column: 1 / -1;
|
|
grid-row: 1 / -1;
|
|
}
|
|
|
|
.flex_col {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.content {
|
|
width: 100%;
|
|
height: 100%;
|
|
position: relative;
|
|
|
|
.left-top-text {
|
|
position: absolute;
|
|
left: 5px;
|
|
top: 5px;
|
|
color: #ddd;
|
|
z-index: 1;
|
|
font-size: 12px;
|
|
|
|
.cd-info {
|
|
color: #ddd;
|
|
font-size: 18px;
|
|
}
|
|
|
|
.subject-info {
|
|
color: #f44336;
|
|
padding: 5px 0px;
|
|
margin: 0;
|
|
}
|
|
}
|
|
|
|
.top-center-tool {
|
|
position: absolute;
|
|
left: 50%;
|
|
top: 5px;
|
|
transform: translateX(-50%);
|
|
z-index: 1;
|
|
|
|
.toggle-visit-container {
|
|
display: flex;
|
|
}
|
|
|
|
.arrw_icon {
|
|
width: 20px;
|
|
height: 20px;
|
|
background-color: #3f3f3f;
|
|
text-align: center;
|
|
line-height: 20px;
|
|
border-radius: 10%;
|
|
}
|
|
|
|
.arrow_text {
|
|
height: 20px;
|
|
line-height: 20px;
|
|
background-color: #00000057;
|
|
color: #fff;
|
|
padding: 0 10px;
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
|
|
.right-slider-box {
|
|
position: absolute;
|
|
right: 1px;
|
|
height: calc(100% - 140px);
|
|
transform: translateY(-50%);
|
|
top: calc(50% - 30px);
|
|
width: 10px;
|
|
background: #333;
|
|
z-index: 1;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.right-slider-box:after {
|
|
content: '';
|
|
position: absolute;
|
|
bottom: -20px;
|
|
left: 0;
|
|
height: 20px;
|
|
width: 100%;
|
|
background: #333;
|
|
}
|
|
|
|
.slider {
|
|
height: 20px;
|
|
width: 100%;
|
|
position: absolute;
|
|
top: 0;
|
|
z-index: 10;
|
|
background: #9e9e9e;
|
|
cursor: move
|
|
}
|
|
}
|
|
}
|
|
|
|
::v-deep .el-dialog {
|
|
background: #1e1e1e;
|
|
border: 1px solid #ddd;
|
|
color: #ddd;
|
|
|
|
.el-dialog__title {
|
|
color: #fff;
|
|
}
|
|
|
|
.el-input .el-input__inner {
|
|
background-color: transparent;
|
|
color: #ddd;
|
|
border: 1px solid #5e5e5e;
|
|
}
|
|
|
|
.el-input.is-disabled .el-input__inner {
|
|
background-color: #646464a1;
|
|
}
|
|
|
|
.el-form-item__label {
|
|
color: #dfdfdf
|
|
}
|
|
}
|
|
}
|
|
</style>
|