非DICOM工具支持长度、角度 || 非DICOM工具支持区域测量面积、周长(未完成)
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
95428e6f69
commit
505c18b611
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751350116150" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="20392" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M870.4 819.2a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4zM512 179.2a332.8 332.8 0 1 1 0 665.6 332.8 332.8 0 0 1 0-665.6z m0 51.2a281.6 281.6 0 1 0 0 563.2 281.6 281.6 0 0 0 0-563.2zM153.6 102.4a51.2 51.2 0 1 1 0 102.4 51.2 51.2 0 0 1 0-102.4z" fill="#ADAEB8" p-id="20393"></path></svg>
|
After Width: | Height: | Size: 623 B |
|
@ -0,0 +1 @@
|
|||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1751349783728" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="9505" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M838.4 279.466667zM802.133333 814.933333H279.466667c-38.4 0-70.4-32-70.4-70.4V219.733333c0-38.4 32-70.4 70.4-70.4h123.733333c38.4 0 70.4 32 70.4 70.4v339.2h347.733333c2.133333 0-2.133333 0 0 0 25.6-2.133333 51.2 21.333333 51.2 46.933334v136.533333c0 40.533333-32 72.533333-70.4 72.533333z m25.6-179.2c2.133333-29.866667-34.133333-27.733333-34.133333-27.733333H445.866667c-2.133333 0-2.133333-2.133333-4.266667-2.133333h-2.133333c-8.533333-4.266667-12.8-10.666667-12.8-21.333334v-362.666666c0-14.933333-12.8-27.733333-27.733334-27.733334h-117.333333c-14.933333 0-27.733333 12.8-27.733333 27.733334v64h115.2c12.8 0 23.466667 10.666667 23.466666 23.466666 0 12.8-10.666667 23.466667-23.466666 23.466667h-115.2v78.933333h78.933333c12.8 0 23.466667 10.666667 23.466667 23.466667 0 12.8-10.666667 23.466667-23.466667 23.466667h-78.933333v78.933333h115.2c12.8 0 23.466667 10.666667 23.466666 23.466667 0 12.8-10.666667 23.466667-23.466666 23.466666h-115.2v149.333334c0 14.933333 12.8 27.733333 27.733333 27.733333H426.666667v-85.333333c0-12.8 10.666667-25.6 23.466666-25.6 12.8 0 23.466667 10.666667 23.466667 25.6v85.333333h96v-68.266667c0-12.8 10.666667-25.6 23.466667-25.6 12.8 0 23.466667 10.666667 23.466666 25.6V768h78.933334v-85.333333c0-12.8 10.666667-25.6 23.466666-25.6 12.8 0 23.466667 10.666667 23.466667 25.6v85.333333h51.2c14.933333 0 27.733333-12.8 27.733333-27.733333l6.4-104.533334z" p-id="9506"></path></svg>
|
After Width: | Height: | Size: 1.7 KiB |
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div ref="container" style="width:100%;height:100%" class="dicom-container">
|
||||
<!-- 访视阅片 -->
|
||||
<div v-if="readingCategory=== 1 && (CriterionType === 7 || ((CriterionType === 1 || CriterionType === 0) && readingVersionEnum === 1)) " class="reading-wrapper">
|
||||
<div v-if="readingCategory === 1 && (CriterionType === 7 || ((CriterionType === 1 || CriterionType === 0) && readingVersionEnum === 1)) " class="reading-wrapper">
|
||||
<VisitReview :reading-tool="readingTool" />
|
||||
</div>
|
||||
<div v-else-if="(isReadingTaskViewInOrder === 1 || ((isReadingTaskViewInOrder !== 1) && isShow)) && readingCategory=== 1 && CriterionType !== 0" class="reading-wrapper">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div v-loading="loading" class="reading-viewer-container">
|
||||
<!-- 访视阅片 -->
|
||||
<visit-review
|
||||
v-if="taskInfo && taskInfo.ReadingCategory=== 1"
|
||||
v-if="taskInfo && taskInfo.ReadingCategory === 1"
|
||||
/>
|
||||
<!-- 临床数据 -->
|
||||
<el-dialog
|
||||
|
|
|
@ -17,51 +17,61 @@
|
|||
</el-dropdown>
|
||||
</div>
|
||||
<!-- 缩放 -->
|
||||
<div
|
||||
:class="['tool-item', activeTool === 'Zoom' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:reading:button:zoom')"
|
||||
@click.prevent="setToolActive('Zoom')"
|
||||
>
|
||||
<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')"
|
||||
>
|
||||
<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')"
|
||||
>
|
||||
<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
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Length' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:nondicom-show:length')" @click.prevent="setAnnotateToolActive('Length')">
|
||||
<svg-icon icon-class="length" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 箭头工具 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'ArrowAnnotate' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:reading:button:arrowAnnotate')"
|
||||
@click.prevent="setAnnotateToolActive('ArrowAnnotate')"
|
||||
>
|
||||
:title="$t('trials:reading:button:arrowAnnotate')" @click.prevent="setAnnotateToolActive('ArrowAnnotate')">
|
||||
<svg-icon icon-class="arrow" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 角度工具 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Angle' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:dicom-show:Angle')" @click.prevent="setAnnotateToolActive('Angle')">
|
||||
<svg-icon icon-class="cobb" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 矩形工具 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'RectangleROI' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:dicom-show:RectangleRoi')"
|
||||
@click.prevent="setAnnotateToolActive('RectangleROI')"
|
||||
>
|
||||
:title="$t('trials:dicom-show:RectangleRoi')" @click.prevent="setAnnotateToolActive('RectangleROI')">
|
||||
<svg-icon icon-class="rectangle" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 圆形工具 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'CircleROI' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:dicom-show:CircleROI')" @click.prevent="setAnnotateToolActive('CircleROI')">
|
||||
<svg-icon icon-class="oval" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 椭圆工具 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'EllipticalROI' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:dicom-show:EllipticalROI')" @click.prevent="setAnnotateToolActive('EllipticalROI')">
|
||||
<svg-icon icon-class="elliptical" class="svg-icon" />
|
||||
</div>
|
||||
<!-- 自由曲线 -->
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'PlanarFreehandROI' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:reading:button:planarFreehandROI')"
|
||||
@click.prevent="setAnnotateToolActive('PlanarFreehandROI')"
|
||||
>
|
||||
@click.prevent="setAnnotateToolActive('PlanarFreehandROI')">
|
||||
<svg-icon icon-class="polygon" class="svg-icon" />
|
||||
</div>
|
||||
<!-- <div
|
||||
|
@ -74,17 +84,14 @@
|
|||
|
||||
<div
|
||||
:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Eraser' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:dicom-show:Eraser')"
|
||||
@click.prevent="setAnnotateToolActive('Eraser')"
|
||||
>
|
||||
: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 === 'Length' ? 'tool-item-active' : '']"
|
||||
:title="$t('trials:nondicom-show:scale')"
|
||||
@click.prevent="setAnnotateToolActive('Length')"
|
||||
>
|
||||
<svg-icon icon-class="length" class="svg-icon" />
|
||||
: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
|
||||
|
@ -95,11 +102,7 @@
|
|||
<svg-icon icon-class="image" class="svg-icon" />
|
||||
</div> -->
|
||||
<!-- 重置 -->
|
||||
<div
|
||||
class="tool-item"
|
||||
:title="$t('trials:reading:button:reset')"
|
||||
@click.prevent="resetViewport"
|
||||
>
|
||||
<div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport">
|
||||
<svg-icon icon-class="refresh" class="svg-icon" />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -111,112 +114,84 @@
|
|||
<!-- 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"
|
||||
<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)"
|
||||
>
|
||||
@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 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"
|
||||
>
|
||||
<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 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' }"
|
||||
<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)"
|
||||
>
|
||||
@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' }"
|
||||
<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)"
|
||||
>
|
||||
@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 :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 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 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"
|
||||
>
|
||||
<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 v-if="v.currentFileName">{{ v.currentFileName }}</div> -->
|
||||
</div>
|
||||
<div
|
||||
v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo"
|
||||
class="top-center-tool"
|
||||
>
|
||||
<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' }"
|
||||
<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)"
|
||||
>
|
||||
@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' }"
|
||||
<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)"
|
||||
>
|
||||
@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" />
|
||||
<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>
|
||||
|
@ -224,14 +199,8 @@
|
|||
</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-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">
|
||||
|
@ -244,13 +213,8 @@
|
|||
</span>
|
||||
</el-dialog>
|
||||
|
||||
<el-dialog
|
||||
v-if="personalConfigDialog.visible"
|
||||
:visible.sync="personalConfigDialog.visible"
|
||||
:close-on-click-modal="false"
|
||||
:title="personalConfigDialog.title"
|
||||
width="600px"
|
||||
>
|
||||
<el-dialog v-if="personalConfigDialog.visible" :visible.sync="personalConfigDialog.visible"
|
||||
:close-on-click-modal="false" :title="personalConfigDialog.title" width="600px">
|
||||
<Others />
|
||||
</el-dialog>
|
||||
</div>
|
||||
|
@ -277,6 +241,7 @@ 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"
|
||||
const {
|
||||
ToolGroupManager,
|
||||
Enums: csToolsEnums,
|
||||
|
@ -289,7 +254,10 @@ const {
|
|||
PlanarFreehandROITool,
|
||||
SplineROITool,
|
||||
EraserTool,
|
||||
LengthTool
|
||||
LengthTool,
|
||||
EllipticalROITool,
|
||||
CircleROITool,
|
||||
AngleTool
|
||||
// cursors
|
||||
} = cornerstoneTools
|
||||
const { MouseBindings, Events: toolsEvents } = csToolsEnums
|
||||
|
@ -480,10 +448,14 @@ export default {
|
|||
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}`
|
||||
|
@ -495,10 +467,10 @@ export default {
|
|||
toolGroup.addTool(PlanarRotateTool.toolName)
|
||||
toolGroup.addTool(ArrowAnnotateTool.toolName, {
|
||||
arrowHeadStyle: 'standard',
|
||||
changeTextCallback: async(data, eventData, doneChangingTextCallback) => {
|
||||
changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback(await this.customPrompt())
|
||||
},
|
||||
getTextCallback: async(doneChangingTextCallback) => {
|
||||
getTextCallback: async (doneChangingTextCallback) => {
|
||||
return doneChangingTextCallback(await this.customPrompt())
|
||||
}
|
||||
})
|
||||
|
@ -506,6 +478,15 @@ export default {
|
|||
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,
|
||||
|
@ -522,6 +503,10 @@ export default {
|
|||
getTextLines: this.getLengthToolTextLines,
|
||||
cachedStats: false
|
||||
})
|
||||
toolGroup.addTool(LengthscaleTool.toolName, {
|
||||
getTextLines: this.getLengthscaleToolTextLines,
|
||||
cachedStats: false
|
||||
})
|
||||
|
||||
toolGroup.setToolActive(StackScrollTool.toolName, {
|
||||
bindings: [{ mouseButton: MouseBindings.Wheel }]
|
||||
|
@ -532,15 +517,23 @@ export default {
|
|||
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)
|
||||
})
|
||||
|
@ -804,12 +797,12 @@ export default {
|
|||
if (this.activeTool) {
|
||||
toolGroup.setToolPassive(this.activeTool)
|
||||
}
|
||||
if (toolName === 'Length') {
|
||||
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 === 'Length')
|
||||
const idx = annotations.findIndex(i => i.metadata.referencedImageId === imageId && i.metadata.toolName === 'Lengthscale')
|
||||
if (idx > -1) {
|
||||
this.activeTool = ''
|
||||
// 当前图像已存在比例尺!
|
||||
|
@ -874,7 +867,7 @@ export default {
|
|||
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 === 'Length') {
|
||||
if (annotation.metadata.toolName === 'Lengthscale') {
|
||||
this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: null })
|
||||
}
|
||||
},
|
||||
|
@ -893,7 +886,7 @@ export default {
|
|||
const fileList = this.viewportInfos[i].fileList
|
||||
const fileIndex = fileList.findIndex(f => f.Path === path)
|
||||
if (fileIndex === -1) return
|
||||
if (annotation.metadata.toolName === 'Length') {
|
||||
if (annotation.metadata.toolName === 'Lengthscale') {
|
||||
const value = annotation.data.l
|
||||
if (value) {
|
||||
const cachedStats = Object.keys(annotation.data.cachedStats)
|
||||
|
@ -929,7 +922,7 @@ export default {
|
|||
const fileList = this.viewportInfos[i].fileList
|
||||
const fileIndex = fileList.findIndex(f => f.Path === path)
|
||||
if (fileIndex === -1) return
|
||||
if (annotation.metadata.toolName === 'Length') {
|
||||
if (annotation.metadata.toolName === 'Lengthscale') {
|
||||
this.form.annotationObj = {
|
||||
id: '',
|
||||
visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
|
||||
|
@ -996,7 +989,7 @@ export default {
|
|||
viewport.render()
|
||||
this.dialogVisible = false
|
||||
},
|
||||
getLengthToolTextLines(data, targetId) {
|
||||
getLengthscaleToolTextLines(data, targetId) {
|
||||
const cachedVolumeStats = data.cachedStats[targetId]
|
||||
const { length, unit } = cachedVolumeStats
|
||||
if (length === undefined || length === null || isNaN(length)) {
|
||||
|
@ -1013,6 +1006,27 @@ export default {
|
|||
}
|
||||
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 {
|
||||
|
@ -1044,7 +1058,7 @@ export default {
|
|||
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}`)
|
||||
}
|
||||
|
@ -1094,6 +1108,60 @@ export default {
|
|||
|
||||
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, 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
|
||||
},
|
||||
reRound(result, finalPrecision) {
|
||||
if (typeof result === 'string' && result.includes(', ')) {
|
||||
const numStrs = result.split(', ')
|
||||
|
@ -1105,7 +1173,7 @@ export default {
|
|||
processSingle(str, precision) {
|
||||
const num = parseFloat(str)
|
||||
if (isNaN(num)) return 'NaN'
|
||||
|
||||
|
||||
// 保留原极小值处理逻辑
|
||||
if (Math.abs(num) < 0.0001) return str
|
||||
const factor = 10 ** precision
|
||||
|
@ -1113,7 +1181,7 @@ export default {
|
|||
},
|
||||
debounce(callback, delay) {
|
||||
let timerId
|
||||
return function() {
|
||||
return function () {
|
||||
clearTimeout(timerId)
|
||||
timerId = setTimeout(() => {
|
||||
callback.apply(this, arguments)
|
||||
|
@ -1226,9 +1294,10 @@ export default {
|
|||
.none-dicom-viewer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width:100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
|
||||
.tools-wrapper {
|
||||
height: 50px;
|
||||
display: flex;
|
||||
|
@ -1236,6 +1305,7 @@ export default {
|
|||
border-bottom: 1px solid #727272;
|
||||
color: #ddd;
|
||||
padding: 0 5px;
|
||||
|
||||
.tools-left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
@ -1243,6 +1313,7 @@ export default {
|
|||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tool-item {
|
||||
padding: 5px;
|
||||
margin: 0 5px;
|
||||
|
@ -1250,15 +1321,19 @@ export default {
|
|||
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%;
|
||||
|
@ -1267,26 +1342,32 @@ export default {
|
|||
}
|
||||
|
||||
.grid-cell {
|
||||
border: 1px dashed #ccc;;
|
||||
border: 1px dashed #ccc;
|
||||
;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cell_active {
|
||||
border-color: #fafa00!important;
|
||||
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;
|
||||
|
@ -1294,26 +1375,31 @@ export default {
|
|||
color: #ddd;
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
|
||||
.cd-info {
|
||||
color: #ddd;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.subject-info {
|
||||
color:#f44336;
|
||||
color: #f44336;
|
||||
padding: 5px 0px;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.top-center-tool {
|
||||
position: absolute;
|
||||
left:50%;
|
||||
left: 50%;
|
||||
top: 5px;
|
||||
transform: translateX(-50%);
|
||||
z-index: 1;
|
||||
|
||||
.toggle-visit-container {
|
||||
display: flex;
|
||||
}
|
||||
.arrw_icon{
|
||||
|
||||
.arrw_icon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background-color: #3f3f3f;
|
||||
|
@ -1321,15 +1407,17 @@ export default {
|
|||
line-height: 20px;
|
||||
border-radius: 10%;
|
||||
}
|
||||
.arrow_text{
|
||||
|
||||
.arrow_text {
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
background-color: #00000057;
|
||||
color: #fff;
|
||||
padding:0 10px;
|
||||
padding: 0 10px;
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.right-slider-box {
|
||||
position: absolute;
|
||||
right: 1px;
|
||||
|
@ -1341,7 +1429,8 @@ export default {
|
|||
z-index: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
.right-slider-box:after{
|
||||
|
||||
.right-slider-box:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -20px;
|
||||
|
@ -1350,33 +1439,39 @@ export default {
|
|||
width: 100%;
|
||||
background: #333;
|
||||
}
|
||||
|
||||
.slider {
|
||||
height: 20px;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
z-index:10;
|
||||
z-index: 10;
|
||||
background: #9e9e9e;
|
||||
cursor: move
|
||||
}
|
||||
}
|
||||
}
|
||||
::v-deep .el-dialog{
|
||||
|
||||
::v-deep .el-dialog {
|
||||
background: #1e1e1e;
|
||||
border: 1px solid #ddd;
|
||||
color: #ddd;
|
||||
.el-dialog__title{
|
||||
color:#fff;
|
||||
|
||||
.el-dialog__title {
|
||||
color: #fff;
|
||||
}
|
||||
.el-input .el-input__inner{
|
||||
|
||||
.el-input .el-input__inner {
|
||||
background-color: transparent;
|
||||
color: #ddd;
|
||||
border: 1px solid #5e5e5e;
|
||||
}
|
||||
.el-input.is-disabled .el-input__inner{
|
||||
|
||||
.el-input.is-disabled .el-input__inner {
|
||||
background-color: #646464a1;
|
||||
}
|
||||
.el-form-item__label{
|
||||
|
||||
.el-form-item__label {
|
||||
color: #dfdfdf
|
||||
}
|
||||
}
|
||||
|
|
|
@ -264,7 +264,7 @@ export default {
|
|||
if (typeof i.MeasureData === 'string') {
|
||||
i.MeasureData = JSON.parse(i.MeasureData)
|
||||
}
|
||||
if (i.MeasureData.metadata.toolName === 'Length' && this.psArr.findIndex(p => p.NoneDicomFileId === i.NoneDicomFileId) === -1) {
|
||||
if (i.MeasureData.metadata.toolName === 'Lengthscale' && this.psArr.findIndex(p => p.NoneDicomFileId === i.NoneDicomFileId) === -1) {
|
||||
this.psArr.push({ NoneDicomFileId: i.NoneDicomFileId, Path: i.Path, PS: i.MeasureData.data.ps })
|
||||
}
|
||||
return i
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import * as cornerstoneTools from '@cornerstonejs/tools'
|
||||
class LengthscaleTool extends cornerstoneTools.LengthTool {
|
||||
static { this.toolName = 'Lengthscale'; }
|
||||
constructor(
|
||||
toolProps,
|
||||
defaultToolProps
|
||||
) {
|
||||
super(toolProps, defaultToolProps);
|
||||
}
|
||||
}
|
||||
export default LengthscaleTool;
|
Loading…
Reference in New Issue