<template>
  <div
    v-loading="loading"
    :element-loading-text="loadingText"
    element-loading-spinner="el-icon-loading"
    element-loading-background="rgba(0, 0, 0, 0.8)"
    class="read-page-container"
  >
    <!-- 检查列表 -->
    <div class="left-panel">
      <div class="task-container">
        <div class="task-info">
          <div
            v-for="(s, index) in visitTaskList"
            :key="s.VisitTaskId"
            class="task-item"
            :class="{'task-item-active': activeTaskId==s.VisitTaskId}"

            @click.prevent="toggleTask(s, index)"
          >{{ s.TaskBlindName }}</div>
        </div>
      </div>
      <div v-loading="sLoading" class="study-info">
        <div
          v-for="s in visitTaskList"
          v-show="activeTaskId === s.VisitTaskId"
          :key="s.VisitTaskId"
          style="height:100%;"
        >
          <study-list
            v-if="selectArr.includes(s.VisitTaskId) && s.StudyList.length > 0"
            :ref="s.VisitTaskId"
            :visit-task-info="s"
            :marked-series-ids="markedSeriesIds"
            @activeSeries="activeSeries"
            @showMultiFrame="showMultiFrame"
          />

        </div>
      </div>
    </div>

    <!-- 视口及表单 -->
    <div class="middle-panel">
      <div class="dicom-viewer">
        <!-- tools -->
        <div class="tools-wrapper">
          <div class="tools-left">
            <!-- 布局 -->
            <div
              :class="['tool-item', isFusion ? 'tool-disabled' : '']"
              :title="$t('trials:reading:button:layout')"
              @click.stop="showPanel($event, 'layout')"
              @mouseleave="toolMouseout"
            >
              <div class="dropdown">
                <div class="icon">
                  <svg-icon icon-class="layout" class="svg-icon" />
                  <i class="el-icon-arrow-down" style="color:#fff;" />
                </div>
                <div class="dropdown-content layout-content">
                  <ul style="width:50px" class="layout-content-ul">
                    <li class="layout_flex_row" @click.stop="changeLayout(1)">
                      <div class="layout_box_1_1">
                        A
                      </div>
                    </li>
                    <li class="layout_flex_row" @click.stop="changeLayout(2)">
                      <div class="layout_box_1_1">
                        A
                      </div>
                      <div class="layout_box_1_1">
                        A
                      </div>
                    </li>
                    <li v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1" class="layout_flex_row" @click.stop="changeLayout(3)">
                      <div class="layout_box_1_1">
                        A
                      </div>
                      <div class="layout_box_1_1">
                        B
                      </div>
                    </li>

                    <li class="layout_flex_column" @click.stop="changeLayout(4)">

                      <div style="flex:1;display: flex;width:100%;">
                        <div class="layout_box_1_2">
                          A
                        </div>
                        <div class="layout_box_1_2">
                          A
                        </div>
                      </div>
                      <div style="flex:1;display: flex;width:100%;">
                        <div class="layout_box_1_2">
                          A
                        </div>
                        <div class="layout_box_1_2">
                          A
                        </div>
                      </div>
                    </li>
                  </ul>
                </div>
              </div>
            </div>
            <!-- 调窗 -->
            <div
              :class="['tool-item', activeTool === 'WindowLevel' ? 'tool-item-active' : '']"
              :title="$t('trials:reading:button:wwwc')"
              @click.stop="setWindowLevelActive($event)"
              @mouseleave="toolMouseout"
            >
              <div class="dropdown">
                <div class="icon">
                  <svg-icon icon-class="reverse" class="svg-icon" />
                  <i class="el-icon-arrow-down" style="color:#fff;" />
                </div>
                <div class="dropdown-content">
                  <ul style="width:165px;">
                    <li v-for="item in wwwcArr" :key="item.label">
                      <a href="#" @click.stop="changeVoiRange(item)">
                        <div v-if="item.wc !== null" style="display:flex;flex-direction: row;justify-content: space-between;">
                          <div>{{ item.label }}</div>
                          <div>{{ `${item.ww} / ${item.wc}` }}</div>
                        </div>
                        <div v-else style="text-align:left;">
                          {{ item.label }}
                        </div>
                      </a>
                      <el-divider v-if="item.val === 1" class="divider" content-position="center">
                        {{ ` ${$t('trials:reading:title:preset') }` }}
                      </el-divider>
                    </li>
                  </ul>
                </div>
              </div>
            </div>
            <!-- 反色 -->
            <div
              class="tool-item"
              :title="$t('trials:reading:button:reverseColor')"
              @click.prevent="toggleInvert"
            >
              <svg-icon icon-class="reversecolor" class="svg-icon" />
            </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
              class="tool-item"
              :title="$t('trials:reading:button:rotate')"
              @click.stop="showPanel($event)"
              @mouseleave="toolMouseout"
            >
              <div class="dropdown">
                <div
                  class="icon"
                  data-tool="Rotate"
                  :class="[activeTool==='Rotate'?'tool_active':'']"
                >
                  <svg-icon icon-class="rotate" class="svg-icon" />
                  <i class="el-icon-arrow-down" style="color:#fff;" />
                </div>
                <div class="dropdown-content">
                  <ul style="width:100px;">
                    <li v-for="rotate in rotateOptions" :key="rotate.label" style="text-align:left;">
                      <a href="#" @click.prevent="setViewportRotate(rotate.val)">
                        {{ rotate.label }}
                      </a>
                    </li>
                  </ul>
                </div>
              </div>
            </div>
            <!-- 适应图像或窗口 -->
            <div
              class="tool-item"
              :title="forceFitToWindow ? `${$t('trials:reading:button:fitWindow')}` : `${$t('trials:reading:button:fitImage')}`"
              @click.prevent="fitToType(forceFitToWindow)"
            >
              <svg-icon v-if="forceFitToWindow" icon-class="fitToWindow" class="svg-icon" />
              <svg-icon v-else icon-class="fitToImage" class="svg-icon" />
            </div>
            <!--融合-->
            <div v-if="readingTool === 2" class="tool-item" :title="$t('trials:lugano:button:fusion')" @click.prevent="openFusion">
              <svg-icon icon-class="fusion" 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)"
              @mouseenter="enter($event,tool.toolName)"
            >
              <svg-icon :icon-class="tool.icon" class="svg-icon" />
            </div>
            <!-- 清除标注 -->
            <div
              v-if="criterionType === 0"
              :class="['tool-item', activeTool === 'Eraser' ? 'tool-item-active' : '']"
              :title="$t('trials:dicom-show:Eraser')"
              @click.prevent="setToolActive('Eraser')"
            >
              <svg-icon icon-class="clear" class="svg-icon" />
            </div>
            <div class="tool-frame">
              <!-- 第一帧 -->
              <div :title="$t('trials:dicom-show:firstframe')" class="icon" @click.prevent="scrollPage(0)">
                <svg-icon icon-class="firstframe" class="svg-icon" />
              </div>
              <!-- 上一帧 -->
              <div :title="$t('trials:dicom-show:previousframe')" class="icon" @click.prevent="scrollPage(-1)">
                <svg-icon icon-class="previousframe" class="svg-icon" />
              </div>
              <!-- 播放/暂停 -->
              <div
                v-if="clipPlaying"
                :title="$t('trials:dicom-show:stop')"
                class="icon"
                @click.prevent="toggleClipPlay(false)"
              >
                <svg-icon icon-class="stop" class="svg-icon" />
              </div>
              <div
                v-else
                :title="$t('trials:dicom-show:play')"
                class="icon"
                @click.prevent="toggleClipPlay(true)"
              >
                <svg-icon icon-class="play" class="svg-icon" />
              </div>
              <!-- 下一帧 -->
              <div :title="$t('trials:dicom-show:nextframe')" class="icon" @click.prevent="scrollPage(1)">
                <svg-icon icon-class="nextframe" class="svg-icon" />
              </div>
              <!-- 最后一帧 -->
              <div :title="$t('trials:dicom-show:lastframe')" class="icon" @click.prevent="scrollPage(99999)">
                <svg-icon icon-class="lastframe" class="svg-icon" />
              </div>
              <select v-model="fps" :title="$t('trials:dicom-show:speed')" class="select-wrapper" :disabled="clipPlaying">
                <!-- 默认值 -->
                <option :value="5">5</option>
                <option :value="10">10</option>
                <option :value="15">15</option>
                <option :value="20">20</option>
                <option :value="25">25</option>
                <option :value="30">30</option>
              </select>
            </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 customizeStandards" :key="i.toolName" style="text-align:left;">
                      <a href="#" @click.prevent="setMoreToolActive(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>
            <!-- 伪彩 -->
            <template v-if="readingTool === 2">
              <colorMap v-show="isFusion" ref="colorMap" @setColorMap="setColorMap" @voiChange="voiChange" />
            </template>
          </div>

          <div>
            <!-- 手册 -->
            <el-button
              v-if="taskInfo && taskInfo.ExistsManual"
              type="text"
              @click="previewManuals"
            >
              {{ $t('trials:reading:button:handbooks') }}
            </el-button>
            <!-- 临床数据 -->
            <el-button
              v-if="taskInfo && taskInfo.IsExistsClinicalData"
              type="text"
              @click="previewCD(taskInfo.VisitTaskId)"
            >
              {{ $t('trials:reading:button:clinicalData') }}
            </el-button>
            <!-- 个性化配置 -->
            <el-button
              type="text"
              @click="previewConfig"
            >
              {{ $t('trials:reading:button:customCfg') }}
            </el-button>
          </div>
        </div>
        <div class="content-wrapper">
          <!-- viewports -->
          <div class="viewports-wrapper">
            <div ref="container" class="grid-container">
              <div :class="[ 'viewports-box', isFusion ? 'viewports-box-down' : '' ]" :style="gridStyle">
                <div
                  v-for="(v, index) in cellsMax"
                  v-show="index < cells.length"
                  :key="`viewport-${index}`"
                  :style="cellStyle"
                  :class="['grid-cell', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
                  @dblclick="toggleFullScreen($event, index)"
                  @click="activeViewport(index)"
                >
                  <Viewport
                    :ref="`viewport-${index}`"
                    :data-viewport-uid="`viewport-${index}`"
                    :rendering-engine-id="renderingEngineId"
                    :viewport-id="`viewport-${index}`"
                    :viewport-index="index"
                    @activeViewport="activeViewport"
                    @toggleTaskByViewport="toggleTaskByViewport"
                    @previewCD="previewCD"
                    @renderAnnotations="renderAnnotations"
                  />
                </div>
              </div>
              <div v-if="readingTool === 2" :class="[ 'viewports-box', !isFusion ? 'viewports-box-down' : '' ]" :style="gridStyle">
                <div
                  v-for="(v, index) in cellsMax"
                  v-show="index < cells.length"
                  :key="`viewport-fusion-${index}`"
                  :style="cellStyle"
                  :class="['grid-cell', index === activeViewportIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
                  @dblclick="toggleFullScreen($event, index)"
                  @click="activeViewport(index)"
                >
                  <PetCtViewport
                    :ref="`viewport-fusion-${index}`"
                    :data-viewport-uid="`viewport-fusion-${index}`"
                    :rendering-engine-id="renderingEngineId"
                    :viewport-id="`viewport-fusion-${index}`"
                    :viewport-index="index"
                    @activeViewport="activeViewport"
                    @toggleTaskByViewport="toggleTaskByViewport"
                    @previewCD="previewCD"
                    @renderAnnotations="renderAnnotations"
                    @upperRangeChange="upperRangeChange"
                  />
                </div>
              </div>
            </div>
          </div>
          <!-- 表单 -->
          <div class="form-wrapper">
            <div
              v-for="s in visitTaskList"
              v-show="lastViewportTaskId === s.VisitTaskId"
              :key="s.VisitTaskId"
              style="height: 100%;"
            >
              <mRecisit
                v-if="lastViewportTaskId && criterionType === 7 && lastViewportTaskIds.includes(s.VisitTaskId)"
                :ref="`ecrf_${s.VisitTaskId}`"
                :reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
                :last-viewport-task-id="lastViewportTaskId"
                :visit-info="s"
                @removeAnnotation="removeAnnotation"
                @getScreenshots="getScreenshots"
                @setMarkName="setMarkName"
                @imageLocation="imageLocation"
                @resetAnnotations="resetAnnotations"
                @getAnnotations="getAnnotations"
                @setToolToTarget="setToolToTarget"
              />
              <recisit
                v-else-if="lastViewportTaskId && criterionType === 1 && lastViewportTaskIds.includes(s.VisitTaskId)"
                :ref="`ecrf_${s.VisitTaskId}`"
                :reading-task-state="currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
                :last-viewport-task-id="lastViewportTaskId"
                :visit-info="s"
                @removeAnnotation="removeAnnotation"
                @getScreenshots="getScreenshots"
                @setMarkName="setMarkName"
                @imageLocation="imageLocation"
                @resetAnnotations="resetAnnotations"
                @getAnnotations="getAnnotations"
                @setToolToTarget="setToolToTarget"
              />
              <customize-question-list
                v-else-if="lastViewportTaskId && criterionType === 0 && lastViewportTaskIds.includes(s.VisitTaskId)"
                :ref="`ecrf_${s.VisitTaskId}`"
                :reading-task-state="taskInfo && currentVisitInfo.VisitTaskId === taskInfo.VisitTaskId ? readingTaskState : 2"
                :last-viewport-task-id="lastViewportTaskId"
                :visit-info="s"
                @resetAnnotations="resetAnnotations"
                @setReadingTaskState="setReadingTaskState"
                @viewCustomAnnotationSeries="viewCustomAnnotationSeries"
                @getCustomScreenshots="getCustomScreenshots"
                @setReadingToolActive="setReadingToolActive"
                @setReadingToolPassive="setReadingToolPassive"
              />
            </div>
          </div>
        </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"
    >
      <custom-wwwc-form :ww="activeViewportWW" :wc="activeViewportWC" @close="customWwc.visible = false" @setWwwc="setWwwc" />
    </el-dialog>
    <!-- 手册 -->
    <el-dialog
      v-if="manualsDialog.visible"
      :visible.sync="manualsDialog.visible"
      :custom-class="manualsDialog.isFullscreen?'manuals-full-dialog-container':'manuals-dialog-container'"
      :show-close="false"
      :close-on-click-modal="false"
      :fullscreen="manualsDialog.isFullscreen"
    >
      <span slot="title" class="dialog-footer">
        <!-- 手册 -->
        <span>{{ $t('trials:reading:button:handbooks') }}</span>
        <span style="position: absolute;right: 20px;font-size: 20px;">
          <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" style="margin-right:10px;cursor: pointer;" @click="manualsDialog.isFullscreen=!manualsDialog.isFullscreen" />
          <svg-icon icon-class="close" style="cursor: pointer;" @click="manualsDialog.visible = false" />
        </span>
      </span>
      <div style="height: 100%;margin:0;">
        <Manuals :trial-id="trialId" />
      </div>
    </el-dialog>
    <!-- 个性化配置 -->
    <el-dialog
      v-if="personalConfigDialog.visible"
      :visible.sync="personalConfigDialog.visible"
      :close-on-click-modal="false"
      :title="personalConfigDialog.title"
      width="600px"
    >
      <el-tabs v-model="personalConfigDialog.activeName" class="personal_config">
        <!-- 热键 -->
        <el-tab-pane :label="$t('trials:reading:tab:hotkeys')" name="1">
          <Hotkeys v-if="personalConfigDialog.activeName === '1'" :reading-tool="0" @reset="resetHotkeyList" />
        </el-tab-pane>
        <!-- W/L模板 -->
        <el-tab-pane :label="$t('trials:reading:tab:wlTemplate')" name="2">
          <WL v-if="personalConfigDialog.activeName === '2'" @getWwcTpl="getWwcTpl" />
        </el-tab-pane>
        <!-- 其他 -->
        <el-tab-pane :label="$t('trials:reading:tab:others')" name="3">
          <Others v-if="personalConfigDialog.activeName === '3'" />
        </el-tab-pane>
      </el-tabs>

    </el-dialog>
    <!-- 临床数据 -->
    <el-dialog
      :visible.sync="clinicalDataVisible"
      :custom-class="isClinicalDataFullscreen?'cd-full-dialog-container':'cd-dialog-container'"
      :show-close="false"
      :close-on-click-modal="false"
      :fullscreen="isClinicalDataFullscreen"
    >
      <span slot="title" class="dialog-footer">
        <div style="position: absolute;right: 20px;top: 10px;color: #000;">
          <svg-icon :icon-class="isClinicalDataFullscreen?'exit-fullscreen':'fullscreen'" style="cursor: pointer;font-size: 20px;" @click="isClinicalDataFullscreen=!isClinicalDataFullscreen" />
          <svg-icon icon-class="dClose" style="cursor: pointer;font-size: 25px;margin-left: 10px;" @click="clinicalDataVisible = false" />
        </div>
      </span>
      <div style="height: 100%;margin:0;display: flex;flex-direction: column;">
        <clinical-data
          v-if="clinicalDataVisible"
          style="flex: 1"
          :trial-id="trialId"
          :subject-id="taskInfo.SubjectId"
          :visit-task-id="cdVisitTaskId"
          :is-reading-show-subject-info="taskInfo.IsReadingShowSubjectInfo"
        />
      </div>

    </el-dialog>
    <el-dialog
      :visible.sync="fusionVisible"
      :close-on-click-modal="false"
      :title="$t('trials:lugano:button:record')"
      width="850px"
    >
      <FusionForm v-if="fusionVisible" :active-task-index="activeTaskIndex" :task-list="visitTaskList" @close="closeFusion" @fusion="handleFusion" />
    </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 { getRelatedVisitTask, getReadingVisitStudyList, getTableAnswerRowInfoList, deleteCustomTag, getCriterionReadingInfo } from '@/api/trials'
import { getDoctorShortcutKey, getUserWLTemplateList } from '@/api/user'
import { getCustomTag, submitCustomTag } from '@/api/reading'
import { getToken } from '@/utils/auth'
import {
  RenderingEngine,
  Enums,
  // imageLoader,
  // metaData,
  volumeLoader,
  getRenderingEngine,
  eventTarget,
  utilities as csUtils,
  cache
} from '@cornerstonejs/core'
import {
  annotation
} from '@cornerstonejs/tools'
import * as cornerstoneTools from '@cornerstonejs/tools'
import initLibraries from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/initLibraries'
import html2canvas from 'html2canvas'
import { getTools, getCustomizeStandardsTools, config } from './toolConfig'
import StudyList from './StudyList'
import Viewport from './Viewport'
import PetCtViewport from './PetCtViewport'
import mRecisit from './mRecist/QuestionList'
import recisit from './Recist/QuestionList'
import customizeQuestionList from './customize/QuestionList'
import CustomWwwcForm from '@/views/trials/trials-panel/reading/dicoms/components/CustomWwwcForm'
import DicomEvent from '@/views/trials/trials-panel/reading/dicoms/components/DicomEvent'
import Manuals from '@/views/trials/trials-panel/reading/dicoms/components/Manuals'
import Hotkeys from '@/views/trials/trials-panel/reading/dicoms/components/Hotkeys'
import WL from '@/views/trials/trials-panel/reading/dicoms/components/WL'
import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others'
import ClinicalData from '@/views/trials/trials-panel/reading/clinical-data'
import FusionForm from './FusionForm.vue'
import colorMap from './colorMap.vue'
import RectangleROITool from './tools/RectangleROITool'
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
import { getNetWorkSpeed, setNetWorkSpeedSize, workSpeedclose } from "@/utils"
const { visibility } = annotation
const { ViewportType, Events } = Enums
const renderingEngineId = 'myRenderingEngine'
const {
  ToolGroupManager,
  Enums: csToolsEnums,
  StackScrollTool,
  ScaleOverlayTool,
  PanTool,
  ZoomTool,
  WindowLevelTool,
  WindowLevelRegionTool,
  PlanarRotateTool,
  LengthTool,
  BidirectionalTool,
  ArrowAnnotateTool,
  // RectangleROITool,
  PlanarFreehandROITool,
  CircleROITool,
  AngleTool,
  CobbAngleTool,
  EraserTool,
  MIPJumpToClickTool,
  VolumeRotateTool,
  synchronizers
  // cursors
} = cornerstoneTools
const { createCameraPositionSynchronizer, createVOISynchronizer } = synchronizers
const newStyles = {
  global: {
    color: 'rgb(255, 0, 0)',
    colorHighlighted: 'rgb(0, 255, 0)',
    colorSelected: 'rgb(255, 0, 0)',
    colorLocked: 'rgb(255, 0, 0)',
    lineWidth: '1',
    lineDash: '',
    shadow: true,
    textBoxVisibility: true,
    textBoxFontFamily: 'Helvetica Neue, Helvetica, Arial, sans-serif',
    textBoxFontSize: '14px',
    textBoxColor: 'rgb(255, 0, 0)',
    textBoxColorHighlighted: 'rgb(0, 255, 0)',
    textBoxColorSelected: 'rgb(255, 0, 0)',
    textBoxColorLocked: 'rgb(255, 0, 0)',
    textBoxBackground: '',
    textBoxLinkLineWidth: '1',
    textBoxLinkLineDash: '2,3',
    textBoxShadow: true,
    markerSize: '10'
  }
}
annotation.config.style.setDefaultToolStyles(newStyles)
const { MouseBindings, Events: toolsEvents } = csToolsEnums
export default {
  name: 'ReadPage',
  components: {
    StudyList,
    Viewport,
    PetCtViewport,
    mRecisit,
    recisit,
    customizeQuestionList,
    CustomWwwcForm,
    Manuals,
    Hotkeys,
    WL,
    Others,
    ClinicalData,
    FusionForm,
    colorMap,
    downloadDicomAndNonedicom,
    uploadDicomAndNonedicom,
  },
  props: {
    readingTool: {
      type: Number,
      default: 2
    }
  },
  data() {
    return {
      loading: false,
      trialId: '',
      visitTaskList: [],
      selectArr: [],
      taskInfo: null,
      activeTaskId: null,
      activeTaskIndex: -1,
      activeStudyIndex: -1,
      activeSeriesIndex: -1,
      currentVisitInfo: null,
      layout: 1,
      cellsMax: 4,
      rows: 1,
      cols: 1,
      fullScreenIndex: null,
      activeViewportIndex: 0,
      activeTool: '',
      readingTaskState: 2,
      renderingEngineId: renderingEngineId,
      sLoading: false,
      renderedTaskIds: [],
      criterionType: null,
      tools: [],
      rotateOptions: [
        { label: this.$t('trials:reading:button:rotateDefault'), val: 1 },
        { label: this.$t('trials:reading:button:rotateVertical'), val: 2 },
        { label: this.$t('trials:reading:button:rotateHorizontal'), val: 3 },
        { label: this.$t('trials:reading:button:rotateTurnLeft'), val: 4 },
        { label: this.$t('trials:reading:button:rotateTurnRight'), val: 5 }
      ],
      defaultWwwc: [
        { label: this.$t('trials:reading:button:wwwcDefault'), val: -1, ww: null, wc: null }, // 默认值
        { label: this.$t('trials:reading:button:wwwcCustom'), val: 0, ww: null, wc: null }, // 自定义
        { label: this.$t('trials:reading:button:wwwcRegion'), val: 1, ww: null, wc: null }, // 区域窗宽
        { label: 'CT Brain', wc: 40, ww: 80 },
        { label: 'CT Lungs', wc: -400, ww: 1500 },
        { label: 'CT Abdomen', wc: 60, ww: 400 },
        { label: 'CT Liver', wc: 40, ww: 400 },
        { label: 'CT Bone', wc: 300, ww: 1500 },
        { label: 'CT Bone1', wc: 0, ww: 0 }
      ],
      wwwcArr: [],
      customWwc: { visible: false, title: this.$t('trials:reading:dagTitle:wwwcCustom') }, // 自定义调窗
      personalConfigDialog: { visible: false, title: this.$t('trials:reading:button:customCfg'), activeName: '1' }, // 个性化配置
      activeViewportWW: null,
      activeViewportWC: null,
      clipPlaying: false,
      fps: 15,
      manualsDialog: { visible: false, isFullscreen: false },
      hotKeyList: [],
      forceFitToWindow: false,
      isShowAnnotations: true,
      clinicalDataVisible: false,
      isClinicalDataFullscreen: false,
      cdVisitTaskId: '',
      lastViewportTaskId: '',
      digitPlaces: 2,
      instanceInfo: {},
      lastViewportTaskIds: [],
      markedSeriesIds: [],
      customizeStandards: [],

      fusionVisible: false,
      isFusion: false,
      studyList: [],
      volumeData: {},
      fusionSerieId: {},
      loadingText: null,
      toolNames: ['Length', 'Bidirectional', 'RectangleROI', 'ArrowAnnotate', 'CircleROI', 'Eraser'],
      // resetAnnotation: false , // 是否初始化标记 （融合时使用）
      saveCustomAnnotationTimer: 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)
    },
    viewportKey() {
      return this.isFusion ? 'viewport-fusion' : 'viewport'
    },
  },
  watch: {
    currentReadingTaskState(){console.log(this.currentReadingTaskState,'currentReadingTaskState')},
    activeTaskId: {
      immediate: true,
      handler(id) {
        if (!id) return
        // this.addHistoryAnnotations(id)
      }
    },
    activeViewportIndex: {
      immediate: true,
      handler(index) {
        let series = null
        if (this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`] && this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0]) {
          this.clipPlaying = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].playClipState
          series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
        } else {
          this.clipPlaying = false
          this.fps = 15
        }
        if (index === this.cells.length - 1 && series) {
          this.lastViewportTaskId = series.TaskInfo.VisitTaskId
          this.currentVisitInfo = series.TaskInfo
        }
      }
    },
    lastViewportTaskId: {
      immediate: true,
      handler(id) {
        if (!id) return
        if (!this.lastViewportTaskIds.includes(id)) {
          this.lastViewportTaskIds.push(id)
        }
      }
    },
    readingTaskState: {
      immediate: true,
      handler(state) {
        if (state === 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.isReadingTaskViewInOrder = this.taskInfo.IsReadingTaskViewInOrder
    this.criterionType = this.taskInfo.CriterionType
    const digitPlaces = Number(localStorage.getItem('digitPlaces'))
    this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
    if (this.criterionType === 0) {
      this.tools = getCustomizeStandardsTools(this.taskInfo.ReadingToolList)
      const toolNames = this.tools.map(i => i.toolName)
      this.customizeStandards = config.customizeStandards.filter(item => !toolNames.includes(item.toolName))
    } else {
      this.tools = getTools(this.criterionType)
    }

    this.trialId = this.$route.query.trialId
    this.readingTaskState = this.taskInfo.ReadingTaskState
    if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
      this.rows = 1
      this.cols = 2
      this.activeViewportIndex = 1
    }

    this.$nextTick(() => {
      this.loadRelatedTasks()
      this.initLoader()
      this.getWwcTpl()
    })

    DicomEvent.$on('isCanActiveNoneDicomTool', data => {
      this.open.postMessage({ type: 'isCanActiveNoneDicomTool', data: data }, window.location)
    })
    DicomEvent.$on('removeNoneDicomMeasureData', data => {
      this.open.postMessage({ type: 'removeNoneDicomMeasureData', data: data }, window.location)
    })
    DicomEvent.$on('addNoneDicomMeasureData', data => {
      this.open.postMessage({ type: 'addNoneDicomMeasureData', data: data }, window.location)
    })
  },
  methods: {
    // 加载当前任务关联的任务信息
    async loadRelatedTasks() {
      this.loading = true
      try {
        const params = {
          visitTaskId: this.taskInfo.VisitTaskId
        }
        const res = await getRelatedVisitTask(params)
        let currentTaskIndex = 0
        let currentTaskId = ''
        this.visitTaskList = []
        for (let i = 0; i < res.Result.length; i++) {
          const item = res.Result[i]
          let studyList = []
          let annotations = []
          let annotationUIDs = []
          let keyImages = []
          let isInit = false
          if (item.IsCurrentTask) {
            currentTaskIndex = i
            currentTaskId = item.VisitTaskId
          }
          if (item.IsCurrentTask || (this.taskInfo.IsReadingTaskViewInOrder === 1 && !this.taskInfo.IsBaseLineTask && item.IsBaseLineTask)) {
            const res = await this.loadTaskDetails(item, i)
            isInit = true
            studyList = res ? res.studyList : []
            annotations = res ? res.annotations : []
            annotationUIDs = res ? res.annotationUIDs : []
            keyImages = res ? res.keyImages : []
            if (!this.selectArr.includes(item.VisitTaskId)) {
              this.selectArr.push(item.VisitTaskId)
            }
            if (item.IsCurrentTask) {
              this.markedSeriesIds = []
              annotations.map(i => {
                if (i.MeasureData && i.MeasureData.seriesId) {
                  this.markedSeriesIds.push(i.MeasureData.seriesId)
                }
              })
            }
          }

          this.visitTaskList.push({
            ...item,
            StudyList: studyList,
            Annotations: annotations,
            KeyImages: keyImages,
            AnnotationUIDs: annotationUIDs,
            IsInit: isInit
          })
        }
        this.activeTaskId = currentTaskId
        this.activeTaskIndex = currentTaskIndex
        this.$nextTick(() => {
          this.setInitSeries()
        })

        this.loading = false
      } catch (e) {
        console.log(e)
        this.loading = false
      }
    },
    // 加载检查及标注信息
    async loadTaskDetails(taskInfo, taskIndex) {
      return new Promise(async(resolve, reject) => {
        try {
          const sujectVisitId = taskInfo.VisitId
          const taskId = taskInfo.VisitTaskId
          // 获取检查信息
          const keyImages = []
          const res1 = await getReadingVisitStudyList(this.trialId, sujectVisitId, taskId)
          let keyStudyIndex = -1
          let keySeriesIndex = -1
          const arr = res1.Result
          arr.forEach((study, studyIndex) => {
            study.SeriesList.forEach((series, seriesIndex) => {
              const imageIds = []
              const stack = []
              series.InstanceInfoList.forEach((instance, instanceIndex) => {
                if (study.IsCriticalSequence) {
                  keyStudyIndex = studyIndex
                  keySeriesIndex = seriesIndex
                  keyImages.push({ Id: instance.Id, Path: instance.Path, KeyFramesList: instance.KeyFramesList, KeyStudyIndex: studyIndex, KeySeriesIndex: seriesIndex })
                } else {
                  const i = keyImages.findIndex(k => k.Id === instance.Id)
                  if (i > -1) {
                    keyImages[i].StudyIndex = studyIndex
                    keyImages[i].SeriesIndex = seriesIndex
                  }
                  const nFrames = instance.NumberOfFrames || 0
                  if (nFrames === 0) {
                    // 单帧
                    stack.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
                  } else {
                    // 多帧
                    for (let i = 0; i < nFrames; i++) {
                      const newImageId = `wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}&frame=${i + 1}`
                      stack.push(newImageId)
                    }
                  }
                  imageIds.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
                  this.instanceInfo[instance.Id] = { taskIndex, studyIndex, seriesIndex }
                }
              })
              series.Stack = stack
              series.ImageIds = imageIds
              series.SliceIndex = 0
              series.LoadedImageCount = 0
              series.LoadedImageProgress = 0
              series.TaskInfo = Object.assign({}, taskInfo)
              series.StudyIndex = studyIndex
              series.SeriesIndex = seriesIndex
            })
          })
          if (keyStudyIndex > -1 && keySeriesIndex > -1 && keyImages.length > 0) {
            const keyImageIds = []
            const keyStack = []
            keyImages.forEach(instance => {
              if (instance.KeyFramesList.length > 0) {
                instance.KeyFramesList.map(i => {
                  keyStack.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}&frame=${i}`)
                })
              } else {
                keyStack.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
              }
              keyImageIds.push(`wadouri:${this.OSSclientConfig.basePath}${instance.Path}?instanceId=${instance.Id}`)
            })
            res1.Result[keyStudyIndex].SeriesList[keySeriesIndex].ImageIds = keyImageIds
            res1.Result[keyStudyIndex].SeriesList[keySeriesIndex].Stack = keyStack
          }
          // 获取标注信息
          let res2 = null
          if (this.criterionType === 0) {
            res2 = await getCustomTag({ visitTaskId: taskId })
          } else {
            res2 = await getTableAnswerRowInfoList(taskId)
          }
          const annotationUIDs = []
          const annotations = res2.Result.map(i => {
            if (typeof i.MeasureData === 'string' && i.MeasureData) {
              i.MeasureData = JSON.parse(i.MeasureData)
              if (this.criterionType === 0) {
                i.MeasureData.id = i.Id
                i.MeasureData.markId = i.MarkId
              }
              annotationUIDs.push(i.MeasureData.annotationUID)
            }
            return i
          })
          // return { studyList: arr, annotations: annotations, annotationUIDs, keyImages }
          resolve({ studyList: arr, annotations: annotations, annotationUIDs, keyImages })
        } catch (e) {
          console.log(e)
          reject(e)
        }
      })
    },
    // 设置初始化序列信息
    setInitSeries() {
      const seriesArr = []
      let activeStudyIndex = -1
      let activeSeriesIndex = -1
      const studyList = this.visitTaskList[this.activeTaskIndex].StudyList.filter(i => i.IsDicom)
      const seriesList = studyList.map(s => s.SeriesList).flat()
      if (this.taskInfo.IsReadingTaskViewInOrder === 0) {
        // 完全随机（默认一个视口，展示第一个序列）
        const series = this.getRelatedSeries(this.visitTaskList[this.activeTaskIndex])
        seriesArr.push(series)
        activeStudyIndex = series.StudyIndex
        activeSeriesIndex = series.SeriesIndex
      } else if (this.taskInfo.IsReadingTaskViewInOrder === 1) {
        // 按时间顺序（默认基线时显示一个视口，展示第一个序列；随访时显示基线和当前随访的序列）
        if (this.taskInfo.IsBaseLine) {
          // 基线默认显示第一个序列
          const series = this.getRelatedSeries(this.visitTaskList[this.activeTaskIndex])
          seriesArr.push(series)
          activeStudyIndex = series.StudyIndex
          activeSeriesIndex = series.SeriesIndex
        } else {
          // 随访
          const i = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
          const baseSeries = this.getRelatedSeries(this.visitTaskList[i])
          seriesArr.push(baseSeries)
          const followUpSeries = this.getRelatedSeries(this.visitTaskList[this.activeTaskIndex], baseSeries)
          seriesArr.push(followUpSeries)
          activeStudyIndex = followUpSeries.StudyIndex
          activeSeriesIndex = followUpSeries.SeriesIndex
        }
      } else if (this.taskInfo.IsReadingTaskViewInOrder === 2) {
        // 受试者内随机（默认两个视口，显示第一个序列和第二个序列；如果只有一个序列则两个视口均显示这个序列）
        if (seriesList.length === 1) {
          seriesArr.push(seriesList[0], seriesList[0])
          activeStudyIndex = seriesList[0].StudyIndex
          activeSeriesIndex = seriesList[0].SeriesIndex
        } else if (seriesArr.length > 1) {
          seriesArr.push(seriesList[0], seriesList[1])
          activeStudyIndex = seriesList[1].StudyIndex
          activeSeriesIndex = seriesList[1].SeriesIndex
        }
      }

      if (activeStudyIndex > -1 && activeSeriesIndex > -1) {
        seriesArr.map((i, index) => {
          this.$refs[`${this.viewportKey}-${index}`][0].setSeriesInfo(i)
        })
        const visitTaskId = this.visitTaskList[this.activeTaskIndex].VisitTaskId
        this.lastViewportTaskId = visitTaskId
        this.currentVisitInfo = this.visitTaskList[this.activeTaskIndex]
        this.$refs[visitTaskId][0].setSeriesActive(activeStudyIndex, activeSeriesIndex)
      }
    },
    // 初始化加载器
    async initLoader() {
      await initLibraries()
      cache.setMaxCacheSize(6 * 1024 * 1024 * 1024)
      let renderingEngine = getRenderingEngine(renderingEngineId)
      if (!renderingEngine) {
        renderingEngine = new RenderingEngine(renderingEngineId)
      }
      const element1 = this.$refs['viewport-0'][0].$el
      const element2 = this.$refs['viewport-1'][0].$el
      const element3 = this.$refs['viewport-2'][0].$el
      const element4 = this.$refs['viewport-3'][0].$el

      let viewportInputArray = [
        {
          viewportId: 'viewport-0',
          type: ViewportType.STACK,
          element: element1
        },
        {
          viewportId: 'viewport-1',
          type: ViewportType.STACK,
          element: element2
        },
        {
          viewportId: 'viewport-2',
          type: ViewportType.STACK,
          element: element3
        },
        {
          viewportId: 'viewport-3',
          type: ViewportType.STACK,
          element: element4
        }
      ]
      let viewportIds = ['viewport-0', 'viewport-1', 'viewport-2', 'viewport-3']
      const fusionViewportIds = ['viewport-fusion-0', 'viewport-fusion-1', 'viewport-fusion-2', 'viewport-fusion-3']
      if (this.readingTool === 2) {
        const fusionElement1 = this.$refs['viewport-fusion-0'][0].$el
        const fusionElement2 = this.$refs['viewport-fusion-1'][0].$el
        const fusionElement3 = this.$refs['viewport-fusion-2'][0].$el
        const fusionElement4 = this.$refs['viewport-fusion-3'][0].$el
        const arr = [
          {
            viewportId: 'viewport-fusion-0',
            type: ViewportType.ORTHOGRAPHIC,
            element: fusionElement1,
            defaultOptions: {
              orientation: Enums.OrientationAxis.AXIAL
            }
          },
          {
            viewportId: 'viewport-fusion-1',
            type: ViewportType.ORTHOGRAPHIC,
            element: fusionElement2,
            defaultOptions: {
              orientation: Enums.OrientationAxis.AXIAL,
              background: [1, 1, 1]
            }
          },
          {
            viewportId: 'viewport-fusion-2',
            type: ViewportType.ORTHOGRAPHIC,
            element: fusionElement3,
            defaultOptions: {
              orientation: Enums.OrientationAxis.AXIAL
            }
          },
          {
            viewportId: 'viewport-fusion-3',
            type: ViewportType.ORTHOGRAPHIC,
            element: fusionElement4,
            defaultOptions: {
              orientation: Enums.OrientationAxis.CORONAL,
              background: [1, 1, 1]
            }
          }
        ]
        viewportInputArray = [...viewportInputArray, ...arr]
        viewportIds = viewportIds.concat(fusionViewportIds)
      }
      renderingEngine.setViewports(viewportInputArray)
      this.addAnnotationListeners()
      cornerstoneTools.addTool(StackScrollTool)
      cornerstoneTools.addTool(PanTool)
      cornerstoneTools.addTool(ZoomTool)
      cornerstoneTools.addTool(WindowLevelTool)
      cornerstoneTools.addTool(WindowLevelRegionTool)
      cornerstoneTools.addTool(PlanarRotateTool)
      cornerstoneTools.addTool(ArrowAnnotateTool)
      cornerstoneTools.addTool(RectangleROITool)
      cornerstoneTools.addTool(PlanarFreehandROITool)
      cornerstoneTools.addTool(EraserTool)
      cornerstoneTools.addTool(LengthTool)
      cornerstoneTools.addTool(BidirectionalTool)
      cornerstoneTools.addTool(ScaleOverlayTool)
      cornerstoneTools.addTool(CircleROITool)
      cornerstoneTools.addTool(AngleTool)
      cornerstoneTools.addTool(CobbAngleTool)
      cornerstoneTools.addTool(MIPJumpToClickTool)
      cornerstoneTools.addTool(VolumeRotateTool)

      viewportIds.forEach((viewportId, i) => {
        // const toolGroupId = `viewport-${i}`
        const toolGroupId = viewportId
        const toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
        toolGroup.addViewport(viewportId, renderingEngineId)
        toolGroup.addTool(StackScrollTool.toolName)
        toolGroup.addTool(ScaleOverlayTool.toolName)

        toolGroup.addTool(PanTool.toolName)
        toolGroup.addTool(ZoomTool.toolName)
        toolGroup.addTool(WindowLevelTool.toolName)
        toolGroup.addTool(WindowLevelRegionTool.toolName)
        toolGroup.addTool(PlanarRotateTool.toolName)
        toolGroup.addTool(ArrowAnnotateTool.toolName, {
          arrowHeadStyle: 'standard',
          changeTextCallback: async(data, eventData, doneChangingTextCallback) => {
            return doneChangingTextCallback(data.text)
          },
          getTextCallback: async(doneChangingTextCallback) => {
            return doneChangingTextCallback('Annotation')
          }
        })
        toolGroup.addTool(RectangleROITool.toolName, {
          cachedStats: false,
          getTextLines: this.criterionType === 0 ? this.getCustomRectangleROIToolTextLines : this.getRectangleROIToolTextLines
        })
        toolGroup.addTool(PlanarFreehandROITool.toolName, {
          allowOpenContours: false,
          cachedStats: false,
          getTextLines: this.getPlanarFreehandROIToolTextLines
        })

        toolGroup.addTool(EraserTool.toolName)
        toolGroup.addTool(LengthTool.toolName, {
          getTextLines: this.getLengthToolTextLines
          // cachedStats: false
        })
        toolGroup.addTool(BidirectionalTool.toolName, {
          // cachedStats: true
          getTextLines: this.getBidirectionalToolTextLines
        })
        toolGroup.addTool(CircleROITool.toolName, {
          getTextLines: this.getCircleROIToolTextLines
        })
        toolGroup.addTool(AngleTool.toolName, {
          getTextLines: this.getAngleToolTextLines
        })
        toolGroup.addTool(CobbAngleTool.toolName, {
          getTextLines: this.getCobbAngleToolTextLines
        })
        if (toolGroupId === 'viewport-fusion-3') {
          toolGroup.addTool(VolumeRotateTool.toolName)
          toolGroup.setToolActive(VolumeRotateTool.toolName, {
            bindings: [
              {
                mouseButton: MouseBindings.Wheel // mouse wheel
              }
            ]
          })
          toolGroup.addTool(MIPJumpToClickTool.toolName, {
            targetViewportIds: fusionViewportIds
          })

          // Set the initial state of the tools, here we set one tool active on left click.
          // This means left click will draw that tool.
          toolGroup.setToolActive(MIPJumpToClickTool.toolName, {
            bindings: [
              {
                mouseButton: MouseBindings.Primary // Left Click
              }
            ]
          })
        }
        toolGroup.setToolActive(StackScrollTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Wheel }]
        })
        toolGroup.setToolActive(ZoomTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Secondary }]
        })
        toolGroup.setToolActive(PanTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Auxiliary }]
        })
        // toolGroup.setToolEnabled(ScaleOverlayTool.toolName);
        // toolGroup.setToolPassive(PanTool.toolName)
        // toolGroup.setToolPassive(ZoomTool.toolName)
        toolGroup.setToolPassive(WindowLevelTool.toolName)
        toolGroup.setToolPassive(WindowLevelRegionTool.toolName)
        toolGroup.setToolPassive(PlanarRotateTool.toolName)

        if (this.readingTaskState < 2) {
          toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
          toolGroup.setToolPassive(RectangleROITool.toolName)
          toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
          toolGroup.setToolPassive(LengthTool.toolName)
          toolGroup.setToolPassive(BidirectionalTool.toolName)
          toolGroup.setToolPassive(CircleROITool.toolName)
          toolGroup.setToolPassive(AngleTool.toolName)
          toolGroup.setToolPassive(CobbAngleTool.toolName)
        } else {
          toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
          toolGroup.setToolEnabled(RectangleROITool.toolName)
          toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
          toolGroup.setToolEnabled(LengthTool.toolName)
          toolGroup.setToolEnabled(BidirectionalTool.toolName)
          toolGroup.setToolEnabled(CircleROITool.toolName)
          toolGroup.setToolEnabled(AngleTool.toolName)
          toolGroup.setToolEnabled(CobbAngleTool.toolName)
        }
        toolGroup.setToolPassive(EraserTool.toolName)
      })

      eventTarget.addEventListener('cornerstoneimageloadprogress', this.imageLoadProgress)
      console.log(Events, toolsEvents)
      if (this.readingTool === 2) {
        this.setUpSynchronizers()
      }
    },
    // 影像下载进度回调
    imageLoadProgress(e) {
      const { detail } = e
      const percentComplete = detail.percentComplete
      const imageId = detail.imageId
      const params = this.getInstanceInfo(imageId)
      const instanceId = params.instanceId
      const idxObj = this.instanceInfo[instanceId]
      if (!(idxObj && typeof idxObj === 'object')) return
      if (!(this.instanceInfo[instanceId].hasOwnProperty('percentComplete'))) {
        this.instanceInfo[instanceId].percentComplete = 0
      }
      // if (!params.hasOwnProperty('idx')) return
      // const indexArr = params.idx.split('|')
      // if (indexArr.length < 3) return
      const taskIndex = idxObj.taskIndex
      const studyIndex = idxObj.studyIndex
      const seriesIndex = idxObj.seriesIndex
      const isCriticalSequence = this.visitTaskList[taskIndex].StudyList[studyIndex].IsCriticalSequence
      const keyImages = this.visitTaskList[taskIndex].KeyImages
      const series = this.visitTaskList[taskIndex].StudyList[studyIndex].SeriesList[seriesIndex]
      let file = series.find(item => item.ImageId === imageId)
      if (file) {
        getNetWorkSpeed()
        setNetWorkSpeedSize(percentComplete, file.FileSize, imageId)
      }
      if (percentComplete === 100) {
        workSpeedclose()
      }
      this.setImageLoadedProgress(series, percentComplete, instanceId)
      if (!isCriticalSequence && series.IsBeMark && keyImages.length > 0) {
        const i = keyImages.findIndex(i => i.Id === params.instanceId)
        if (i === -1) return
        const keyStudyIndex = parseInt(keyImages[i].KeyStudyIndex)
        const keySeriesIndex = parseInt(keyImages[i].KeySeriesIndex)
        const keySeries = this.visitTaskList[taskIndex].StudyList[keyStudyIndex].SeriesList[keySeriesIndex]
        this.setImageLoadedProgress(keySeries, percentComplete, instanceId)
      }
    },
    // 设置图像下载进度信息
    setImageLoadedProgress(series, percentComplete, instanceId) {
      let loadedImageCount = series.LoadedImageCount
      if (percentComplete === 100) {
        ++loadedImageCount
        this.$set(series, 'LoadedImageCount', loadedImageCount)
      }
      const newLoadedImageProgress = series.LoadedImageProgress - this.instanceInfo[instanceId].percentComplete + percentComplete
      this.instanceInfo[instanceId].percentComplete = percentComplete
      this.$set(series, 'LoadedImageProgress', newLoadedImageProgress)
    },
    addHistoryAnnotations(taskId) {
      // if (this.renderedTaskIds.includes(taskId)) return
      // this.renderedTaskIds.push(taskId)
      // let taskIdx = this.visitTaskList.findIndex(i=>i.VisitTaskId === taskId)
      // if (taskIdx=== -1) return
      // const annotations = this.visitTaskList[taskIdx].Annotations
      // annotations.map(i => {
      //   if (i.MeasureData) {
      //     const annotation = i.MeasureData
      //     cornerstoneTools.annotation.state.addAnnotation(annotation)
      //     if (this.visitTaskList[taskIdx].ReadingTaskState === 2) {
      //       cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
      //     }
      //   }
      // })
    },
    renderAnnotations(series) {
      const taskId = series.TaskInfo.VisitTaskId
      if (!taskId || this.renderedTaskIds.includes(taskId)) return
      this.renderedTaskIds.push(taskId)
      const taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === taskId)
      if (taskIdx === -1) return
      const annotations = this.visitTaskList[taskIdx].Annotations
      annotations.map(i => {
        if (i.MeasureData && !Object.hasOwn(i.MeasureData, 'isDicomReading')) {
          const annotation = i.MeasureData
          annotation.highlighted = false
          cornerstoneTools.annotation.state.addAnnotation(annotation)
          if (this.visitTaskList[taskIdx].ReadingTaskState === 2) {
            cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
          }
        }
      })
    },
    addAnnotationListeners() {
      const debouncedCallback = this.debounce((evt) => {
        this.criterionType === 0 ? this.customAnnotationModifiedListener(evt) : this.annotationModifiedListener(evt)
      }, 100)
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_MODIFIED,
        (evt) => {
          debouncedCallback(evt)
        }
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_COMPLETED,
        this.criterionType === 0 ? this.customAnnotationCompletedListener : this.annotationCompletedListener
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_REMOVED,
        this.criterionType === 0 ? this.customAnnotationRemovedListener : this.annotationRemovedListener
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_SELECTION_CHANGE,
        this.criterionType === 0 ? this.customAnnotationSelectionChangeListener : this.annotationSelectionChangeListener
      )

      // eventTarget.addEventListener(
      //   toolsEvents.ANNOTATION_ADDED,
      //   this.annotationAddedListener
      // )
      // eventTarget.addEventListener(
      //   toolsEvents.TOOL_MODE_CHANGED,
      //   this.toolModeChanged
      // )
    },
    toolModeChanged(e) {
      console.log(e)
      const arr = cornerstoneTools.annotation.state.getAllAnnotations()
      // if (arr)
      console.log(arr)
    },
    annotationAddedListener(e) {

    },

    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 series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const referencedImageId = annotation.metadata.referencedImageId
        const params = this.getInstanceInfo(referencedImageId)
        annotation.visitTaskId = series.TaskInfo.VisitTaskId
        annotation.studyId = series.StudyId
        annotation.seriesId = series.Id
        annotation.instanceId = params.instanceId
        annotation.sliceThickness = series.SliceThickness
        annotation.numberOfFrames = isNaN(parseInt(params.frame)) ? null : parseInt(params.frame)
        annotation.markTool = annotation.metadata.toolName

        // this.$refs['ecrf'].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
        this.$refs[`ecrf_${this.lastViewportTaskId}`][0].setAnnotation({ annotation, toolName: annotation.metadata.toolName })
        this.markedSeriesIds.push(series.Id)
      }

      this.setToolsPassive()
    },
    annotationModifiedListener(e) {
      console.log('Modified')
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation.highlighted) return
      if (!annotation) return
      if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        // this.$refs['ecrf'].modifyAnnotation({ annotation, toolName: annotation.metadata.toolName })
        this.$refs[`ecrf_${this.lastViewportTaskId}`][0].modifyAnnotation({ annotation, toolName: annotation.metadata.toolName })
      }
      this.setToolsPassive()
    },
    annotationRemovedListener(e) {
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation) return
      if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
        const index = this.markedSeriesIds.indexOf(annotation.seriesId)
        if (index !== -1) {
          this.markedSeriesIds.splice(index, 1)
        }
      }
    },
    async customAnnotationCompletedListener(e) {
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation) return
      const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
      if (i === -1) {
        this.setToolsPassive()
        return
      }
      if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const referencedImageId = annotation.metadata.referencedImageId
        const params = this.getInstanceInfo(referencedImageId)
        annotation.visitTaskId = series.TaskInfo.VisitTaskId
        annotation.studyId = series.StudyId
        annotation.seriesId = series.Id
        annotation.instanceId = params.instanceId
        annotation.sliceThickness = series.SliceThickness
        annotation.numberOfFrames = isNaN(parseInt(params.frame)) ? null : parseInt(params.frame)
        annotation.markTool = annotation.metadata.toolName
        this.markedSeriesIds.push(series.Id)
        const operateStateEnum = this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].operateStateEnum
        const markName = await this.customPrompt(!this.isNumber(operateStateEnum))

        if (markName) {
          annotation.data.label = markName
          if (annotation.metadata.toolName === 'ArrowAnnotate') {
            annotation.data.text = markName
          }
          if (this.isNumber(operateStateEnum)) {
            this.$refs[`ecrf_${series.TaskInfo.VisitTaskId}`][0].bindAnnotationToQuestion(annotation)
          } else {
            if (this.saveCustomAnnotationTimer) {
              clearTimeout(this.saveCustomAnnotationTimer)
              this.saveCustomAnnotationTimer = null
            }
            this.saveCustomAnnotationTimer = setTimeout(()=>{this.saveCustomAnnotation(annotation)},500)
          }
        }
      }

      this.setToolsPassive()
    },
    validMarkName(markName) {
      const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
      const i = annotations.findIndex(i => i.visitTaskId === this.taskInfo.VisitTaskId && i.data.label === markName)
      return i > -1
    },
    async saveCustomAnnotation(annotation) {
      try {
        const measureData = Object.assign({}, annotation)
        const params = {}
        await this.getScreenshots({
            visitTaskId: this.visitTaskId,
            annotation
          },async (base64Str) =>{
            const pictureObj = await this.uploadScreenshots(`${Date.now()}`, base64Str)
            let picturePath = pictureObj.isSuccess ? this.$getObjectName(pictureObj.result.url) : ''
            params.PicturePath = picturePath
            params.MarkTool = measureData.markTool
            params.OrderMarkName = measureData.data.label
            params.VisitTaskId = this.taskInfo.VisitTaskId
            params.StudyId = annotation.studyId
            params.SeriesId = annotation.seriesId
            params.InstanceId = annotation.instanceId
            params.Id = annotation.id ? annotation.id : ''
            params.MeasureData = JSON.stringify(measureData)
            params.NumberOfFrames = annotation.numberOfFrames
            params.MarkId = annotation.annotationUID
            const res = await submitCustomTag(params)
            annotation.id = res.Result
            annotation.markId = params.MarkId
          })
        
      } catch (e) {
         this.loading = false
        console.log(e)
      }
    },
    customAnnotationModifiedListener(e) {
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation.highlighted) return
      if (!annotation) return
      const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
      if (i === -1) {
        this.setToolsPassive()
        return
      }
      if (!annotation.data.label) return
      if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const operateStateEnum = this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].operateStateEnum
        const isBound = this.$refs[`ecrf_${annotation.visitTaskId}`][0].verifyAnnotationIsBound(annotation)
        if (isBound || this.isNumber(operateStateEnum)) {
          this.$refs[`ecrf_${series.TaskInfo.VisitTaskId}`][0].updateAnnotationToQuestion(annotation)
        } else {
          if (this.saveCustomAnnotationTimer) {
            clearTimeout(this.saveCustomAnnotationTimer)
            this.saveCustomAnnotationTimer = null
          }
          this.saveCustomAnnotationTimer = setTimeout(()=>{this.saveCustomAnnotation(annotation)},1000)
        }
      }
      this.setToolsPassive()
    },
    async customAnnotationRemovedListener(e) {
      const { annotation } = e.detail
      try {
        // if ( this.resetAnnotation && this.isFusion ) return false
        if (!annotation) return false
        if (this.readingTaskState === 2) {
          const errorMsg = { message: 'annotation Not allowed to operate' }
          throw errorMsg
        }
        const i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
        if (i === -1) {
          // 临时标记
          return
        }
        if (annotation.visitTaskId === this.taskInfo.VisitTaskId) {
          const isBound = this.$refs[`ecrf_${annotation.visitTaskId}`][0].verifyAnnotationIsBound(annotation)
          if (isBound && this.activeTool === 'Eraser') {
            // '该标记已与问题进行绑定，不允许删除！'
            this.$alert(this.$t('dicom3D:ReadPage:alert:MarkToQuestionNoDel'))
            const errorMsg = { message: 'annotation Not allowed to operate' }
            throw errorMsg
          }
        }

        if (annotation.visitTaskId === this.taskInfo.VisitTaskId && annotation.seriesId) {
          if (this.activeTool === 'Eraser') {
            await this.$confirm(
              this.$t('trials:trials-list:table:isDeleted') +
              annotation.data.label +
              '?'
            )
            if (annotation.markId) {
              deleteCustomTag(annotation.markId)
            }else if (annotation.id) {
              deleteCustomTag(annotation.id)
            }
          }
          const index = this.markedSeriesIds.indexOf(annotation.seriesId)
          if (index !== -1) {
            this.markedSeriesIds.splice(index, 1)
          }
          const renderingEngine = getRenderingEngine(renderingEngineId)
          for (let i = 0; i < this.cells.length; i++) {
            const viewportId = `${this.viewportKey}-${i}`
            const viewport = renderingEngine.getViewport(viewportId)
            viewport.render()
          }
        } else {
          const errorMsg = { message: 'annotation Not allowed to operate' }
          throw errorMsg
        }
      } catch (e) {
        cornerstoneTools.annotation.state.addAnnotation(annotation)
        const renderingEngine = getRenderingEngine(renderingEngineId)
        for (let i = 0; i < this.cells.length; i++) {
          const viewportId = `${this.viewportKey}-${i}`
          const viewport = renderingEngine.getViewport(viewportId)
          viewport.render()
        }
        console.log(e)
      }
    },
    removeAnnotation(annotation) {
      cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
      const renderingEngine = getRenderingEngine(renderingEngineId)
      for (let i = 0; i < this.cells.length; i++) {
        const viewportId = `${this.viewportKey}-${i}`
        const viewport = renderingEngine.getViewport(viewportId)
        viewport.render()
      }
    },
    customAnnotationSelectionChangeListener(e) {
      if (this.readingTaskState === 2) return
      const { detail } = e
      const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
      const i = annotations.findIndex(i => i.annotationUID === detail.selection[0])
      if (i > -1) {
        if (annotations[i].visitTaskId !== this.taskInfo.VisitTaskId) {
          return
        } else {
          this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].bindAnnotationToQuestion(annotations[i])
        }
      }
    },
    annotationSelectionChangeListener(e) {},
    async getAnnotations(visitTaskId) {
      if (this.readingTaskState === 2) return
      const taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
      if (taskIdx === -1) return
      if (!this.visitTaskList[taskIdx].IsCurrentTask) return
      // 获取标注信息
      let res = null
      if (this.criterionType === 0) {
        res = await getCustomTag({ visitTaskId: visitTaskId })
      } else {
        res = await getTableAnswerRowInfoList(visitTaskId)
      }
      const annotationUIDs = []
      const annotations = res.Result.map(i => {
        if (typeof i.MeasureData === 'string' && i.MeasureData) {
          i.MeasureData = JSON.parse(i.MeasureData)
          if (this.criterionType === 0) {
            i.MeasureData.id = i.Id
            i.MeasureData.markId = i.MarkId
          }
          annotationUIDs.push(i.MeasureData.annotationUID)
        }
        return i
      })
      this.$set(this.visitTaskList[taskIdx], 'Annotations', annotations)
      this.$set(this.visitTaskList[taskIdx], 'AnnotationUIDs', annotationUIDs)
    },
    async resetAnnotations(visitTaskId) {
      if (this.readingTaskState === 2) return
      const taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === visitTaskId)
      if (taskIdx === -1) return
      if (!this.visitTaskList[taskIdx].IsCurrentTask) return
      // 获取标注信息
      let res = null
      if (this.criterionType === 0) {
        res = await getCustomTag({ visitTaskId: visitTaskId })
      } else {
        res = await getTableAnswerRowInfoList(visitTaskId)
      }
      const annotations = res.Result.map(i => {
        if (typeof i.MeasureData === 'string' && i.MeasureData) {
          i.MeasureData = JSON.parse(i.MeasureData)
          if (this.criterionType === 0) {
            i.MeasureData.id = i.Id
            i.MeasureData.markId = i.MarkId
          }
        }
        return i
      })
      this.$set(this.visitTaskList[taskIdx], 'Annotations', annotations)
      // 移除病灶
      const arr = cornerstoneTools.annotation.state.getAllAnnotations()
      arr.map(i => {
        if (i.visitTaskId === visitTaskId) {
          cornerstoneTools.annotation.state.removeAnnotation(i.annotationUID)
        }
      })
      annotations.map(i => {
        if (i.MeasureData) {
          const annotation = i.MeasureData
          cornerstoneTools.annotation.state.addAnnotation(annotation)
          this.markedSeriesIds.push(annotation.seriesId)
        }
      })
      const renderingEngine = getRenderingEngine(renderingEngineId)
      for (let i = 0; i < this.cells.length; i++) {
        const viewportId = `${this.viewportKey}-${i}`
        const viewport = renderingEngine.getViewport(viewportId)
        viewport.render()
      }
    },
    setMarkName(obj) {
      const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
      const idx = annotations.findIndex(i => i.annotationUID === obj.annotationUID)
      if (idx === -1) return
      if (annotations[idx].metadata.toolName === 'ArrowAnnotate') {
        annotations[idx].data.text = obj.name
        annotations[idx].data.label = obj.name
      } else {
        annotations[idx].data.label = obj.name
      }
      annotations[idx].data.status = obj.status
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
      const viewport = renderingEngine.getViewport(viewportId)
      viewport.render()
    },
    getLengthToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { length, unit } = cachedVolumeStats
      if (length === undefined || length === null || isNaN(length)) {
        return
      }
      const textLines = []
      if (data.label) {
        textLines.push(data.status ? `${data.label}(${data.status})` : data.label)
      }
      textLines.push(`${parseFloat(length).toFixed(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 = []
      if (data.label) {
        textLines.push(data.label)
      }
      if (area) {
        const areaLine = isEmptyArea
          ? `Area: Oblique not supported`
          : `Area: ${parseFloat(area).toFixed(this.digitPlaces)} ${areaUnit}`
        textLines.push(areaLine)
      }
      if (mean) {
        textLines.push(`Mean: ${parseFloat(mean).toFixed(this.digitPlaces)} ${modalityUnit}`)
      }

      if (Number.isFinite(max)) {
        textLines.push(`Max: ${csUtils.roundNumber(max)} ${modalityUnit}`)
      }

      if (stdDev) {
        textLines.push(`Std Dev: ${csUtils.roundNumber(stdDev)} ${modalityUnit}`)
      }

      if (perimeter) {
        textLines.push(`Perimeter: ${parseFloat(perimeter).toFixed(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 { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats
      const { mean } = cachedVolumeStats

      if (mean === undefined) {
        return
      }

      const textLines = []
      if (data.label) {
        textLines.push(data.status ? `${data.label}(${data.status})` : data.label)
      }

      return textLines
    },
    getCustomRectangleROIToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats

      if (mean === undefined) {
        return
      }

      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      textLines.push(`Area: ${this.reRound(area, this.digitPlaces)} ${areaUnit}`)

      textLines.push(`Mean: ${this.reRound(mean, this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Max: ${this.reRound(max, this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Std Dev: ${this.reRound(stdDev, this.digitPlaces)} ${modalityUnit}`)

      return textLines
    },
    getBidirectionalToolTextLines(data, targetId) {
      const { cachedStats, label } = data
      const { length, width, unit } = cachedStats[targetId]

      const textLines = []

      if (label) {
        textLines.push(data.status ? `${label}(${data.status})` : label)
      }
      if (length === undefined) {
        return textLines
      }
      
      textLines.push(
        `L: ${parseFloat(length).toFixed(this.digitPlaces)} ${unit || unit}`,
        `S: ${parseFloat(width).toFixed(this.digitPlaces)} ${unit}`
      )

      return textLines
    },
    getCircleROIToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const {
        radius,
        radiusUnit,
        area,
        mean,
        stdDev,
        max,
        isEmptyArea,
        areaUnit,
        modalityUnit
      } = cachedVolumeStats
      const textLines = []
      if (data.label) {
        // textLines.push(data.label)
        textLines.push(data.label)
      }

      if (radius) {
        const radiusLine = isEmptyArea
          ? `Radius: Oblique not supported`
          : `Radius: ${this.reRound(radius, this.digitPlaces)} ${radiusUnit}`
        textLines.push(radiusLine)
      }

      if (area) {
        const areaLine = isEmptyArea
          ? `Area: Oblique not supported`
          : `Area: ${parseFloat(area)} ${areaUnit}`
        textLines.push(areaLine)
      }

      if (mean) {
        textLines.push(`Mean: ${this.reRound(mean, this.digitPlaces)} ${modalityUnit}`)
      }

      if (max) {
        textLines.push(`Max: ${this.reRound(max, this.digitPlaces)} ${modalityUnit}`)
      }

      if (stdDev) {
        textLines.push(`Std Dev: ${this.reRound(stdDev, this.digitPlaces)} ${modalityUnit}`)
      }

      return textLines
    },
    getAngleToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { label } = data
      const { angle } = cachedVolumeStats
      if (angle === undefined) {
        return
      }

      if (isNaN(angle)) {
        return [`${angle}`]
      }
      const textLines = []
      if (label) {
        textLines.push(label)
      }
      textLines.push(`${angle.toFixed(this.digitPlaces)} ${String.fromCharCode(176)}`)
      return textLines
    },
    getCobbAngleToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { angle } = cachedVolumeStats
      const { label } = data

      if (angle === undefined) {
        return
      }
      const textLines = []
      if (label) {
        textLines.push(label)
      }
      textLines.push(`${angle.toFixed(this.digitPlaces)} ${String.fromCharCode(176)}`)

      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)
    },
    // 激活工具
    setToolActive(toolName) {
      const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
      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 toolObj = this.tools.find(i => i.toolName === toolName)
      if (!toolObj || toolObj.isDisabled) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
        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
        }
      }
      if (this.criterionType === 0 && this.readingTaskState < 2) {
        this.$refs[`ecrf_${this.taskInfo.VisitTaskId}`][0].resetOperateState()
      }
    },
    setReadingToolActive(toolName) {
      if (this.readingTaskState === 2) return
      if (this.activeTool === toolName) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (this.activeTool) {
          toolGroup.setToolPassive(this.activeTool)
        }
        toolGroup.setToolActive(toolName, {
          bindings: [{ mouseButton: MouseBindings.Primary }]
        })
        this.activeTool = toolName
      }
    },
    setReadingToolPassive() {
      if (this.readingTaskState === 2) return
      if (this.activeTool && this.toolNames.includes(this.activeTool)) {
        const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
        if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
          const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
          const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
          toolGroup.setToolPassive(this.activeTool)
          this.activeTool = ''
        }
      }
    },
    setMoreToolActive(toolName) {
      if (this.readingTaskState === 2) return
      this.setToolsPassive()
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series && series.TaskInfo.VisitTaskId && series.TaskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        toolGroup.setToolActive(toolName, {
          bindings: [{ mouseButton: MouseBindings.Primary }]
        })
        this.activeTool = toolName
      }
    },
    setToolsPassive() {
      if (!this.activeTool) return
      const toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`]
      toolGroupIds.forEach(toolGroupId => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        toolGroup.setToolPassive(this.activeTool)
      })
      this.activeTool = ''
    },
    setToolEnabled() {
      if (!this.activeTool) return
      const toolGroupIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`]
      toolGroupIds.forEach(toolGroupId => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        toolGroup.setToolEnabled(this.activeTool)
      })
      this.activeTool = ''
    },
    // 鼠标移入测量工具时，判断工具是否可激活
    enter(e, toolName) {
      const i = this.tools.findIndex(i => i.toolName === toolName)
      if (i === -1) return
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      const isCurrentTask = series.TaskInfo.IsCurrentTask
      const readingTaskState = this.readingTaskState
      if (!isCurrentTask || readingTaskState >= 2) {
        this.tools[i].isDisabled = true
        e.target.style.cursor = 'not-allowed'
        if (this.activeTool) {
          this.setToolEnabled()
        }
      } else {
        if (this.criterionType === 0) {
          this.tools[i].isDisabled = false
          e.target.style.cursor = 'pointer'
          return
        }
        const obj = this.$refs[`ecrf_${this.lastViewportTaskId}`][0].validTool(toolName, true)
        this.tools[i].disabledReason = obj.reason
        if (!obj.isCanActiveTool) {
          if (this.activeTool === toolName) {
            this.setToolsPassive()
          }
          this.tools[i].isDisabled = true
          e.target.style.cursor = 'not-allowed'
        } else {
          this.tools[i].isDisabled = false
          e.target.style.cursor = 'pointer'
        }
      }
    },
    // 旋转视口
    setViewportRotate(value) {
      this.setToolsPassive()
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
      const viewport = renderingEngine.getViewport(viewportId)
      const type = parseInt(value)
      // 1：默认值；2：垂直翻转；3：水平翻转；4：左转90度；5：右转90度；
      if (type === 1) {
        // viewport.resetCamera()
        // viewport.resetProperties()
        // viewport.render()
        viewport.setViewPresentation({ rotation: 0 })
        viewport.render()
      } else if (type === 2) {
        const { flipVertical } = viewport.getCamera()
        viewport.setCamera({ flipVertical: !flipVertical })
        viewport.render()
      } else if (type === 3) {
        const { flipHorizontal } = viewport.getCamera()
        viewport.setCamera({ flipHorizontal: !flipHorizontal })
        viewport.render()
      } else if (type === 4) {
        const { rotation } = viewport.getViewPresentation()
        viewport.setViewPresentation({ rotation: rotation === 0 ? 270 : rotation - 90 })
        viewport.render()
      } else if (type === 5) {
        const { rotation } = viewport.getViewPresentation()
        viewport.setViewPresentation({ rotation: rotation + 90 })
        viewport.render()
      }
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].rotateOrientationMarkers(type)
    },
    // 重置视口
    resetViewport() {
      this.setToolsPassive()
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
      const viewport = renderingEngine.getViewport(viewportId)
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resetOrientationMarkers()
      viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
      viewport.resetProperties()
      viewport.render()
      renderingEngine.render()
    },
    // 更改视图布局
    async changeLayout(v) {
      this.setToolsPassive()
      this.fullScreenIndex = null
      this.layout = v
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      const seriesArr = []
      if (v === 1) {
        this.rows = 1
        this.cols = 1
        this.activeViewportIndex = 0
        if (typeof series === 'object') {
          seriesArr.push(series)
        }
      } else if (v === 2) {
        this.rows = 1
        this.cols = 2
        this.activeViewportIndex = 1
        if (typeof series === 'object') {
          seriesArr.push(series)
          seriesArr.push(series)
        }
      } else if (v === 3) {
        this.rows = 1
        this.cols = 2
        if (series) {
          const idx = this.visitTaskList.findIndex(i => i.VisitTaskId === series.TaskInfo.VisitTaskId)
          const visitTaskNum = idx > -1 ? this.visitTaskList[idx].VisitTaskNum : -1
          if (visitTaskNum > 0) {
            let visitTaskIdx = -1
            if (this.criterionType === 10) {
              visitTaskIdx = this.visitTaskList.findIndex(i => i.VisitTaskNum === visitTaskNum - 1)
            } else {
              visitTaskIdx = this.visitTaskList.findIndex(i => i.IsBaseLineTask)
            }
            if (visitTaskIdx > -1) {
              if (!this.visitTaskList[visitTaskIdx].IsInit) {
                this.sLoading = true
                try {
                  const res = await this.loadTaskDetails(this.visitTaskList[visitTaskIdx], visitTaskIdx)
                  const studyList = res ? res.studyList : []
                  const annotations = res ? res.annotations : []
                  const keyImages = res ? res.keyImages : []
                  const annotationUIDs = res ? res.annotationUIDs : []
                  this.$set(this.visitTaskList[visitTaskIdx], 'StudyList', studyList)
                  this.$set(this.visitTaskList[visitTaskIdx], 'Annotations', annotations)
                  this.$set(this.visitTaskList[visitTaskIdx], 'KeyImages', keyImages)
                  this.$set(this.visitTaskList[visitTaskIdx], 'AnnotationUIDs', annotationUIDs)
                  this.$set(this.visitTaskList[visitTaskIdx], 'IsInit', true)
                  this.sLoading = false
                } catch (e) {
                  this.sLoading = false
                }
              }
              const relatedSeries = this.getRelatedSeries(this.visitTaskList[visitTaskIdx], series)
              seriesArr.push(relatedSeries)
              seriesArr.push(series)
            }
          } else if (visitTaskNum === 0) {
            seriesArr.push(series)
            seriesArr.push(series)
          }
        }
        this.activeViewportIndex = 1
      } else if (v === 4) {
        this.rows = 2
        this.cols = 2
        if (typeof series === 'object') {
          seriesArr.push(series)
          seriesArr.push(series)
          seriesArr.push(series)
          seriesArr.push(series)
        }
        this.activeViewportIndex = 3
      }
      seriesArr.map((i, index) => {
        this.$refs[`${this.viewportKey}-${index}`][0].setSeriesInfo(i)
      })
      this.$nextTick(() => {
        const renderingEngine = getRenderingEngine(renderingEngineId)
        renderingEngine.resize(true, false)
      })
    },
    // 更改窗宽窗位
    changeVoiRange(v) {
      this.setToolsPassive()
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
      const viewport = renderingEngine.getViewport(viewportId)
      if (v.val === -1) {
        // 默认值
        viewport.resetProperties()
        viewport.render()
      } else if (v.val === 0) {
        // 自定义
        const wwwc = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].imageInfo.wwwc
        this.activeViewportWW = wwwc ? parseInt(wwwc.split('/')[0]) : null
        this.activeViewportWC = wwwc ? parseInt(wwwc.split('/')[1]) : null
        this.customWwc.visible = true
      } else if (v.val === 1) {
        // 区域窗宽窗位
        this.setToolActive('WindowLevelRegion')
      } else {
        const lower = v.wc - v.ww / 2
        const upper = v.wc + v.ww / 2 - 1
        viewport.setProperties({ voiRange: { upper: upper, lower: lower }})
        viewport.render()
      }
    },
    setWindowLevelActive(e) {
      this.setToolActive('WindowLevel')
      this.showPanel(e)
    },
    // 设置窗宽窗位
    setWwwc(v) {
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `${this.viewportKey}-${this.activeViewportIndex}`
      const viewport = renderingEngine.getViewport(viewportId)
      const lower = v.wc - v.ww / 2
      const upper = v.wc + v.ww / 2 - 1
      viewport.setProperties({ voiRange: { upper: upper, lower: lower }})
      viewport.render()
      this.customWwc.visible = false
    },
    // 反色
    toggleInvert() {
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(`${this.viewportKey}-${this.activeViewportIndex}`)
      const { invert } = viewport.getProperties()
      if (this.isFusion) {
        viewport.setProperties({ invert: !invert }, this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].volumeId)
      }
      viewport.setProperties({ invert: !invert })
      viewport.render()
    },
    // 翻页
    scrollPage(type) {
      this.clipPlaying = false
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(type)
    },
    // 播放
    toggleClipPlay(isPlay) {
      this.clipPlaying = !this.clipPlaying
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].toggleClipPlay(isPlay, this.fps)
    },
    // 获取窗宽窗位模板
    async getWwcTpl() {
      try {
        const res = await getUserWLTemplateList()
        const customWwcTpl = []
        res.Result.map(i => {
          customWwcTpl.push({ label: i.TemplateName, wc: i.WL, ww: i.WW })
        })
        this.wwwcArr = [...this.defaultWwwc, ...customWwcTpl]
      } catch (e) {
        console.log(e)
      }
    },
    // 获取热键配置信息
    async getHotKeys() {
      try {
        const res = await getDoctorShortcutKey({ imageToolType: 0 })
        res.Result.map(item => {
          this.hotKeyList.push({ id: item.Id, altKey: item.AltKey, ctrlKey: item.CtrlKey, shiftKey: item.ShiftKey, metaKey: item.MetaKey, key: item.Keyboardkey, code: item.Code, text: item.Text, shortcutKeyEnum: item.ShortcutKeyEnum })
        })
        this.bindHotKey()
      } catch (e) {
        console.log(e)
      }
    },
    // 绑定热键事件
    bindHotKey() {
      const container = this.$refs['container']
      container.addEventListener('keydown', event => {
        const idx = this.hotKeyList.findIndex(i => i.code === event.code && i.ctrlKey === event.ctrlKey && i.shiftKey === event.shiftKey && i.altKey === event.altKey)
        if (idx === -1) return
        const shortcutKeyEnum = this.hotKeyList[idx].shortcutKeyEnum

        if (shortcutKeyEnum === 1) {
          // 前一图像视口
          const viewportIndex = this.activeViewportIndex === 0 ? this.activeViewportIndex : this.activeViewportIndex - 1
          this.activeViewport(viewportIndex)
        } else if (shortcutKeyEnum === 2) {
          // 后一图像视口
          const viewportIndex = this.activeViewportIndex === this.cells.length - 1 ? this.activeViewportIndex : this.activeViewportIndex + 1
          this.activeViewport(viewportIndex)
        } else if (shortcutKeyEnum === 3) {
          // 上一个序列
          const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
          this.$refs[this.activeTaskId][0].getPreviousOrNextSeries(-1, series)
        } else if (shortcutKeyEnum === 4) {
          // 下一个序列
          const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
          this.$refs[this.activeTaskId][0].getPreviousOrNextSeries(1, series)
        } else if (shortcutKeyEnum === 5) {
          // 上一张图像
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(-1)
        } else if (shortcutKeyEnum === 6) {
          // 下一张图像
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].scrollPage(1)
        } else if (shortcutKeyEnum === 7) {
          // 向左旋转
          this.setViewportRotate(4)
        } else if (shortcutKeyEnum === 8) {
          // 向右旋转
          this.setViewportRotate(5)
        } else if (shortcutKeyEnum === 9) {
          // 水平翻转
          this.setViewportRotate(3)
        } else if (shortcutKeyEnum === 10) {
          // 垂直翻转
          this.setViewportRotate(2)
        } else if (shortcutKeyEnum === 11) {
          // 放大
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setZoom(1)
        } else if (shortcutKeyEnum === 12) {
          // 缩小
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setZoom(-1)
        } else if (shortcutKeyEnum === 13) {
          // 适应图像
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(false)
        } else if (shortcutKeyEnum === 14) {
          // 适应窗口
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(true)
        } else if (shortcutKeyEnum === 15) {
          // 截图
        } else if (shortcutKeyEnum === 16) {
          // 反色
          this.toggleInvert()
        } else if (shortcutKeyEnum === 17) {
          // 窗宽/窗位
          const wwwcIdx = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].wwwcIdx
          const newWwwcIdx = wwwcIdx === this.wwwcArr.length - 1 ? 3 : wwwcIdx + 1
          const wwwcTpl = this.wwwcArr[newWwwcIdx]
          this.changeVoiRange(wwwcTpl)
          this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setWwwcIdx(newWwwcIdx)
        } else if (shortcutKeyEnum === 18) {
          // 重置
          this.resetViewport()
        } else if (shortcutKeyEnum === 19) {
          // 显示或隐藏标记
          this.isShowAnnotations = !this.isShowAnnotations
          if (this.isShowAnnotations) {
            visibility.showAllAnnotations()
          } else {
            const annotationUIDs = annotation.state.getAllAnnotations().map((a) => a.annotationUID)
            annotationUIDs.forEach((annotationUID) => {
              visibility.setAnnotationVisibility(annotationUID, false)
            })
          }
          const renderingEngine = getRenderingEngine(renderingEngineId)
          const viewportIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`, `${this.viewportKey}-3`]
          renderingEngine.renderViewports(viewportIds)
        }
        event.stopImmediatePropagation()
        event.stopPropagation()
        event.preventDefault()
      })
    },
    // 重置热键信息
    resetHotkeyList(arr) {
      this.hotKeyList = []
      arr.map(item => {
        this.hotKeyList.push({ id: item.id, altKey: item.keys.controlKey.altKey, ctrlKey: item.keys.controlKey.ctrlKey, shiftKey: item.keys.controlKey.shiftKey, metaKey: item.keys.controlKey.metaKey, key: item.keys.controlKey.key, code: item.keys.controlKey.code, text: item.keys.text, shortcutKeyEnum: item.label })
      })
    },
    fitToType(forceFitToWindow) {
      this.forceFitToWindow = !forceFitToWindow
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].resize(forceFitToWindow)
    },
    // 切换全屏
    toggleFullScreen(e, index) {
      this.fullScreenIndex = this.fullScreenIndex === index ? null : index
      this.activeViewportIndex = index
      if (this.isFusion) {
        const viewportIds = [`${this.viewportKey}-0`, `${this.viewportKey}-1`, `${this.viewportKey}-2`]
        viewportIds.forEach(id => {
          const index = this.$refs[id][0].series.SliceIndex
          this.$refs[id][0].setFullScreen(index)
        })
      }
    },
    async toggleTask(taskInfo, taskIndex) {
      if (this.isFusion) {
        const confirm = await this.$confirm(this.$t('trials:reading:confirm:changeStack'))
        if (!confirm) return false
        this.isFusion = false
        this.fullScreenIndex = null
        this.setToolsPassive()
      }
      if (taskIndex === this.activeTaskIndex) return
      if (!this.selectArr.includes(taskInfo.VisitTaskId)) {
        this.selectArr.push(taskInfo.VisitTaskId)
      }
      this.activeTaskId = taskInfo.VisitTaskId
      this.activeTaskIndex = taskIndex
      if (!taskInfo.IsInit) {
        this.sLoading = true
        try {
          const res = await this.loadTaskDetails(taskInfo, taskIndex)
          const studyList = res ? res.studyList : []
          const annotations = res ? res.annotations : []
          const annotationUIDs = res ? res.annotationUIDs : []
          const keyImages = res ? res.keyImages : []
          this.$set(taskInfo, 'StudyList', studyList)
          this.$set(taskInfo, 'Annotations', annotations)
          this.$set(taskInfo, 'KeyImages', keyImages)
          this.$set(taskInfo, 'AnnotationUIDs', annotationUIDs)
          this.$set(taskInfo, 'IsInit', true)

          this.sLoading = false
        } catch (e) {
          this.sLoading = false
        }
      }
      // this.setToolsPassive()
    },
    async toggleTaskByViewport(obj) {
      const i = this.visitTaskList.findIndex(v => v.VisitTaskNum === obj.visitTaskNum)
      if (i === -1) return
      this.activeTaskId = this.visitTaskList[i].VisitTaskId
      this.activeTaskIndex = i
      if (!this.selectArr.includes(this.activeTaskId)) {
        this.selectArr.push(this.activeTaskId)
      }
      if (!this.visitTaskList[i].IsInit) {
        this.sLoading = true
        try {
          const res = await this.loadTaskDetails(this.visitTaskList[i], i)
          const studyList = res ? res.studyList : []
          const annotations = res ? res.annotations : []
          const annotationUIDs = res ? res.annotationUIDs : []
          const keyImages = res ? res.keyImages : []
          this.$set(this.visitTaskList[i], 'StudyList', studyList)
          this.$set(this.visitTaskList[i], 'Annotations', annotations)
          this.$set(this.visitTaskList[i], 'KeyImages', keyImages)
          this.$set(this.visitTaskList[i], 'AnnotationUIDs', annotationUIDs)
          this.$set(this.visitTaskList[i], 'IsInit', true)
          this.sLoading = false
        } catch (e) {
          this.sLoading = false
        }
      }
      const series = this.getRelatedSeries(this.visitTaskList[i], obj.series)
      this.$nextTick(() => {
        this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(series)
        this.$refs[this.activeTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
        if (this.activeViewportIndex === this.cells.length - 1) {
          this.lastViewportTaskId = series.TaskInfo.VisitTaskId
          this.currentVisitInfo = series.TaskInfo
        }
      })
      this.setToolsPassive()
    },
    async activeSeries(obj) {
      if (this.isFusion) {
        const confirm = await this.$confirm(this.$t('trials:reading:confirm:changeStack'))
        if (!confirm) return false
        this.isFusion = false
        this.setToolsPassive()
        this.rows = 1
        this.cols = 1
        this.activeViewportIndex = 0
        this.fullScreenIndex = null
        return this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
      }
      if (!obj.IsDicom) {
        return this.previewNoneDicoms(obj)
      }
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj)
      this.clipPlaying = false
      this.fps = 15
      if (this.activeViewportIndex === this.cells.length - 1) {
        this.lastViewportTaskId = obj.TaskInfo.VisitTaskId
        this.currentVisitInfo = obj.TaskInfo
      }
      if (obj.TaskInfo.VisitTaskId !== this.taskInfo.VisitTaskId) {
        this.setToolsPassive()
      }
    },
    async showMultiFrame(obj) {
      this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].setSeriesInfo(obj, true)
      this.clipPlaying = false
      this.fps = 15
      if (this.activeViewportIndex === this.cells.length - 1) {
        this.lastViewportTaskId = obj.TaskInfo.VisitTaskId
        this.currentVisitInfo = obj.TaskInfo
      }
      this.setToolsPassive()
    },
    // 激活视口
    activeViewport(index) {
      if (this.activeViewportIndex === index) return
      this.activeViewportIndex = index
      // 切换检查列表
      const series = this.$refs[`${this.viewportKey}-${this.activeViewportIndex}`][0].series
      if (series) {
        const i = this.visitTaskList.findIndex(v => v.VisitTaskId === series.TaskInfo.VisitTaskId)
        if (i > -1) {
          this.activeTaskId = series.TaskInfo.VisitTaskId
          this.activeTaskIndex = i
          this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
        }
      }
      this.setToolsPassive()
    },
    getRelatedSeries(visitTaskInfo, baselineSeries) {
      let obj = {}
      const studyList = visitTaskInfo.StudyList
      const annotations = visitTaskInfo.Annotations
      if (baselineSeries) {
        const seriesList = studyList.filter(i => i.IsDicom).map(s => s.SeriesList).flat()
        if (baselineSeries.IsMarked) {
          const i = annotations.findIndex(i => Object.keys(i.MeasureData).length > 0 && i.OrderMarkName === baselineSeries.MeasureData.OrderMarkName)
          if (i > -1) {
            obj = this.getMarkedSeries(studyList, annotations[i].MeasureData)
          }
        }
        if (Object.keys(obj).length === 0) {
          // 筛选描述相似
          let similarArr = seriesList.map((i, index) => {
            return { similar: this.strSimilarity2Percent(i.Description, baselineSeries.Description), index }
          })
          similarArr = similarArr.sort((a, b) => {
            return b.similar - a.similar
          })
          const idx = similarArr[0] && similarArr[0].similar > 0.85 ? similarArr[0].index : -1
          if (idx > -1) {
            obj = Object.assign({}, seriesList[idx])
            const stack = seriesList[idx].Stack
            const sliceIdx = Math.floor(stack.length * ((baselineSeries.SliceIndex + 1) / baselineSeries.Stack.length))
            // let sliceIdx = Math.floor(imageIds.length / 2)
            obj.SliceIndex = sliceIdx > 0 ? sliceIdx - 1 : 0
          }
        }
        if (Object.keys(obj).length === 0) {
          // 筛选层厚一致
          const idx = seriesList.findIndex(series => series.InstanceCount === baselineSeries.InstanceCount)
          if (idx > -1) {
            obj = Object.assign({}, seriesList[idx])
            const stack = seriesList[idx].Stack
            const sliceIdx = Math.floor(stack.length / 2)
            obj.SliceIndex = sliceIdx > 0 ? sliceIdx - 1 : 0
          }
        }
        if (Object.keys(obj).length === 0) {
          // 筛选层厚为5的序列
          const idx = seriesList.findIndex(series => series.IsDicom && parseInt(series.SliceThickness) === 5)
          if (idx > -1) {
            obj = Object.assign({}, seriesList[idx])
            const stack = seriesList[idx].Stack
            const sliceIdx = Math.floor(stack.length / 2)
            obj.SliceIndex = sliceIdx > 0 ? sliceIdx - 1 : 0
          }
        }
      } else {
        const i = annotations.findIndex(a => Object.keys(a.MeasureData).length > 0)
        if (i > -1) {
          // 有标记时，显示带标记影像所在序列
          obj = this.getMarkedSeries(studyList, annotations[i].MeasureData)
        } else {
          for (let k = 0; k < studyList.length; k++) {
            const seriesIdx = studyList[k].SeriesList.findIndex(s => s.SliceThickness && parseInt(s.SliceThickness) === 5)
            if (seriesIdx > -1) {
              obj = Object.assign({}, studyList[k].SeriesList[seriesIdx])
              const stack = studyList[k].SeriesList[seriesIdx].Stack
              const sliceIdx = Math.floor(stack.length / 2)
              obj.SliceIndex = sliceIdx > 0 ? sliceIdx - 1 : 0
              obj.IsMarked = false
              break
            }
          }
        }
      }
      if (Object.keys(obj).length === 0) {
        const sIdx = studyList.findIndex(s => s.IsDicom)
        if (sIdx > -1) {
          obj = Object.assign({}, studyList[sIdx].SeriesList[0])
          const stack = studyList[sIdx].SeriesList[0].Stack
          const sliceIdx = Math.floor(stack.length / 2)
          obj.SliceIndex = sliceIdx > 0 ? sliceIdx - 1 : 0
          obj.IsMarked = false
        }
      }
      return obj
    },
    getMarkedSeries(studyList, annotation) {
      let obj = {}
      const sIdx = studyList.findIndex(s => s.StudyId === annotation.studyId)
      if (sIdx > -1) {
        const seriesList = studyList[sIdx].SeriesList
        const seriesIdx = seriesList.findIndex(s => s.Id === annotation.seriesId)
        if (seriesIdx > -1) {
          const instanceIdx = seriesList[seriesIdx].InstanceInfoList.findIndex(i => i.Id === annotation.instanceId)
          let filterStr = ''
          if (instanceIdx > -1 && seriesList[seriesIdx].IsExistMutiFrames) {
            if (seriesList[seriesIdx].InstanceInfoList[instanceIdx].NumberOfFrames > 0) {
              filterStr = `instanceId=${annotation.instanceId}&frame=${annotation.numberOfFrames}`
            } else {
              filterStr = `instanceId=${annotation.instanceId}`
            }
          } else {
            filterStr = `instanceId=${annotation.instanceId}`
          }
          const stack = seriesList[seriesIdx].Stack
          const imageIdIdx = stack.findIndex(is => is.includes(filterStr))
          if (imageIdIdx > -1) {
            obj = Object.assign({}, seriesList[seriesIdx])
            obj.SliceIndex = imageIdIdx
            obj.IsMarked = true
            obj.MeasureData = annotation
          }
        }
      }
      return obj
    },
    viewCustomAnnotationSeries(obj) {
      const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
      if (i === -1) return
      const studyList = this.visitTaskList[i].StudyList
      const series = this.getMarkedSeries(studyList, obj.annotation)
      if (series) {
        this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true)
        this.activeViewportIndex = i
        this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
      }
    },
    async getCustomScreenshots(obj, callback) {
      const i = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
      if (i === -1) return
      const studyList = this.visitTaskList[i].StudyList
      const series = this.getMarkedSeries(studyList, obj.annotation)
      if (series) {
        this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].setSeriesInfo(series, true)
        this.activeViewportIndex = i
        this.$refs[series.TaskInfo.VisitTaskId][0].setSeriesActive(series.StudyIndex, series.SeriesIndex)
        const divForDownloadViewport = document.querySelector(
          `div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
        )
        const canvas = await html2canvas(divForDownloadViewport)
        const base64Str = canvas.toDataURL('image/png', 1)
        callback(base64Str)
      }
    },
    async getScreenshots(measureData, callback) {
      if (measureData) {
        await this.imageLocation(measureData)
        const divForDownloadViewport = document.querySelector(
          `div[data-viewport-uid="${this.viewportKey}-${this.activeViewportIndex}"]`
        )
        const canvas = await html2canvas(divForDownloadViewport)
        const base64Str = canvas.toDataURL('image/png', 1)
        callback(base64Str)
      } else {
        callback()
      }
    },
    imageLocation(obj) {
      return new Promise(async resolve => {
        let loading = null
        const index = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.visitTaskId)
        if (index === -1) {
          resolve()
          return
        }
        if (obj.annotationUID) {
          obj.StudyId = obj.studyId
          obj.SeriesId = obj.seriesId
          obj.InstanceId = obj.instanceId
          obj.isMarked = true
        } else {
          obj.isMarked = false
        }

        let firstAddSeries = {}
        let currentAddSeries = {}
        if (this.taskInfo.IsReadingTaskViewInOrder === 1) {
          // 有序
          // 获取病灶第一次出现的访视序列
          let firstAddVisitTaskId = null
          const idx = this.visitTaskList[index].Annotations.findIndex(item => {
            return item.OrderMarkName === obj.lesionName
          })
          if (idx > -1) {
            firstAddVisitTaskId = this.visitTaskList[index].Annotations[idx].FristAddTaskId
            const taskIdx = this.visitTaskList.findIndex(i => i.VisitTaskId === firstAddVisitTaskId)
            if (taskIdx > -1 && !this.visitTaskList[taskIdx].IsInit) {
              loading = this.$loading({ fullscreen: true })
              try {
                const res = await this.loadTaskDetails(this.visitTaskList[taskIdx], taskIdx)
                const studyList = res ? res.studyList : []
                const annotations = res ? res.annotations : []
                const annotationUIDs = res ? res.annotationUIDs : []
                const keyImages = res ? res.keyImages : []
                this.$set(this.visitTaskList[taskIdx], 'StudyList', studyList)
                this.$set(this.visitTaskList[taskIdx], 'Annotations', annotations)
                this.$set(this.visitTaskList[taskIdx], 'KeyImages', keyImages)
                this.$set(this.visitTaskList[taskIdx], 'AnnotationUIDs', annotationUIDs)
                this.$set(this.visitTaskList[taskIdx], 'IsInit', true)
                loading.close()
              } catch (e) {
                loading.close()
              }
            }
            const annotationIdx = this.visitTaskList[taskIdx].Annotations.findIndex(i => i.OrderMarkName === obj.lesionName)
            if (annotationIdx > -1) {
              firstAddSeries = this.getMarkedSeries(this.visitTaskList[taskIdx].StudyList, this.visitTaskList[taskIdx].Annotations[annotationIdx].MeasureData)
            }
          }
          if (obj.isMarked) {
            currentAddSeries = this.getMarkedSeries(this.visitTaskList[index].StudyList, obj)
          }

          if (Object.keys(firstAddSeries).length === 0 && Object.keys(currentAddSeries).length !== 0) {
            firstAddSeries = currentAddSeries
          } else if (Object.keys(firstAddSeries).length === 0 && Object.keys(currentAddSeries).length === 0) {
            this.setToolsPassive()
            if (obj.isActiveTarget) {
              this.setToolToTarget(obj)
            }
            resolve()
            return
          } else if (Object.keys(firstAddSeries).length !== 0 && Object.keys(currentAddSeries).length === 0) {
            // 当前访视序列与首次出现病灶的序列对齐
            // currentAddSeries = this.getRelatedSeries(this.visitTaskList[index], firstAddSeries)

            // if (Object.keys(currentAddSeries).length === 0) {
            //   // 未找到对齐的，则就显示当前最后一个窗口现实的序列信息
            //   currentAddSeries = this.$refs[`viewport-${this.cells.length - 1}`][0].series
            // }

            // 显示当前序列
            currentAddSeries = this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].series
          }
        } else {
          // 无序
          currentAddSeries = this.getMarkedSeries(this.visitTaskList[index].StudyList, obj)
          if (Object.keys(currentAddSeries).length === 0) {
            // 未找到标注序列的，则就显示当前最后一个窗口现实的序列信息cells.length - 1
            currentAddSeries = this.$refs[`${this.viewportKey}-${this.cells.length - 1}`][0].series
          }
          firstAddSeries = currentAddSeries
        }
        for (let i = 0; i < this.cells.length; i++) {
          if (i === this.cells.length - 1) {
            this.$refs[`${this.viewportKey}-${i}`][0].setSeriesInfo(currentAddSeries, true)
            this.activeViewportIndex = i
            this.$refs[currentAddSeries.TaskInfo.VisitTaskId][0].setSeriesActive(currentAddSeries.StudyIndex, currentAddSeries.SeriesIndex)
          } else {
            this.$refs[`${this.viewportKey}-${i}`][0].setSeriesInfo(firstAddSeries, true)
          }
        }
        this.setToolsPassive()
        if (obj.isActiveTarget) {
          this.setToolToTarget(obj)
        }

        resolve()
      })
    },
    setToolToTarget(obj) {
      console.log('setToolToTarget')
      if (obj.visitTaskId === this.taskInfo.VisitTaskId && this.readingTaskState !== 2 && obj.markTool && !obj.isMarked) {
        const toolName = obj.markTool
        if (this.activeTool) {
          this.setToolsPassive()
        }
        const toolGroupId = `${this.viewportKey}-${this.activeViewportIndex}`
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        toolGroup.setToolActive(toolName, {
          bindings: [{ mouseButton: MouseBindings.Primary }]
        })
        this.activeTool = toolName
      }
    },
    setReadingTaskState(state) {
      this.readingTaskState = state
    },
    // 两个字符串的相似程度，并返回相似度百分比
    strSimilarity2Percent(s, t) {
      var l = s.length > t.length ? s.length : t.length
      var d = this.strSimilarity2Number(s, t)
      return Number((1 - d / l).toFixed(4))
    },
    strSimilarity2Number(s, t) {
      var n = s.length; var m = t.length; var d = []
      var i, j, s_i, t_j, cost
      if (n === 0) return m
      if (m === 0) return n
      for (i = 0; i <= n; i++) {
        d[i] = []
        d[i][0] = i
      }
      for (j = 0; j <= m; j++) {
        d[0][j] = j
      }
      for (i = 1; i <= n; i++) {
        s_i = s.charAt(i - 1)
        for (j = 1; j <= m; j++) {
          t_j = t.charAt(j - 1)
          if (s_i === t_j) {
            cost = 0
          } else {
            cost = 1
          }
          d[i][j] = this.Minimum(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost)
        }
      }
      return d[n][m]
    },
    Minimum(a, b, c) {
      return a < b ? (a < c ? a : c) : (b < c ? b : c)
    },
    // 手册
    previewManuals() {
      this.manualsDialog.isFullscreen = false
      this.manualsDialog.visible = true
    },
    // 临床数据
    previewCD(taskId) {
      this.isClinicalDataFullscreen = false
      this.dialogVisible = true
      this.cdVisitTaskId = taskId
      this.clinicalDataVisible = true
    },
    // 个性化配置
    previewConfig() {
      this.personalConfigDialog.activeName = '1'
      this.personalConfigDialog.visible = true
    },
    getInstanceInfo(imageId) {
      const params = {}
      const searchParams = new URLSearchParams(imageId.split('?')[1])
      for (const [key, value] of searchParams.entries()) {
        params[key] = value
      }
      if (isNaN(params.frame)) {
        params.frame = null
      }
      return params
    },
    // 输入标记名称自定义弹窗
    async customPrompt(isShowCancelButton = true) {
      try {
        const that = this
        // 请输入标记名称
        const { value } = await this.$prompt(this.$t('trials:noneDicom:message:msg1'), '', {
          showClose: false,
          showCancelButton: isShowCancelButton,
          beforeClose: (action, instance, done) => {
            if (action === 'confirm') {
              const value = instance.inputValue
              if (!value) {
                that.$message.error(this.$t('trials:customReading:error:validMarkName1'))
              } else if (this.validMarkName(value)) {
                that.$message.error(this.$t('trials:customReading:error:validMarkName'))
              } else {
                done()
              }
            } else {
              done()
            }
          }
        })
        return value
      } catch {
        return null
      }
    },
    isNumber(value) {
      return typeof value === 'number' && value !== null && !isNaN(value)
    },
    showPanel(e, toolName) {
      if (toolName === 'layout' && this.isFusion) return false
      e.currentTarget.firstChild.lastChild.style.display = 'block'
    },
    toolMouseout(e) {
      e.currentTarget.firstChild.lastChild.style.display = 'none'
    },
    debounce(callback, delay) {
      let timerId
      return function() {
        clearTimeout(timerId)
        timerId = setTimeout(() => {
          callback.apply(this, arguments)
        }, delay)
      }
    },
    previewNoneDicoms(obj) {
      var index = this.visitTaskList.findIndex(i => i.VisitTaskId === obj.TaskInfo.VisitTaskId)
      var taskBlindName = this.visitTaskList[index].TaskBlindName
      var token = getToken()
      let subjectId = localStorage.getItem("subjectId")
      const routeData = this.$router.resolve({
        path: `/nonedicoms?subjectId=${subjectId}&trialId=${this.trialId}&visitTaskId=${obj.TaskInfo.VisitTaskId}&taskBlindName=${taskBlindName}&readingTaskState=${this.visitTaskList[index].ReadingTaskState}&TokenKey=${token}`
      })
      this.open = window.open(routeData.href, '_blank')
    },
    // 融合视口相机同步
    setUpSynchronizers() {
      const axialCameraPositionSynchronizer = createCameraPositionSynchronizer(
        'AXIAL_CAMERA_SYNCHRONIZER_ID'
      )
      const ctVoiSynchronizer = createVOISynchronizer('CT_VOI_SYNCHRONIZER_ID', {
        syncInvertState: false,
        syncColormap: false
      })
      const ptVoiSynchronizer = createVOISynchronizer('PT_VOI_SYNCHRONIZER_ID', {
        syncInvertState: false,
        syncColormap: false
      })
      const fusionVoiSynchronizer = createVOISynchronizer('FUSION_VOI_SYNCHRONIZER_ID', {
        syncInvertState: false,
        syncColormap: false
      });
      [
        `viewport-fusion-0`,
        `viewport-fusion-1`,
        `viewport-fusion-2`
      ].forEach((viewportId) => {
        axialCameraPositionSynchronizer.add({
          renderingEngineId: this.renderingEngineId,
          viewportId
        })
      });
      [
        `viewport-fusion-0`
      ].forEach((viewportId) => {
        ctVoiSynchronizer.add({
          renderingEngineId: this.renderingEngineId,
          viewportId
        })
      });
      [
        `viewport-fusion-3`,
        `viewport-fusion-1`
      ].forEach((viewportId) => {
        ptVoiSynchronizer.add({
          renderingEngineId: this.renderingEngineId,
          viewportId
        })
      });
      [
        `viewport-fusion-2`
      ].forEach((viewportId) => {
        fusionVoiSynchronizer.add({
          renderingEngineId,
          viewportId
        })
        ctVoiSynchronizer.addTarget({
          renderingEngineId,
          viewportId
        })
        ptVoiSynchronizer.addTarget({
          renderingEngineId,
          viewportId
        })
      })
    },
    setColorMap(rgbPresetName) {
      const fusionViewportIds = [`viewport-fusion-1`, `viewport-fusion-2`, `viewport-fusion-3`]
      fusionViewportIds.forEach(id => {
        this.$refs[id][0].setPreset(rgbPresetName)
        this.$refs[id][0].renderColorBar(rgbPresetName)
        this.$refs[id][0].setColorMap(rgbPresetName)
      })
    },
    voiChange(v) {
      const fusionViewportIds = [`viewport-fusion-1`, `viewport-fusion-2`, `viewport-fusion-3`]
      fusionViewportIds.forEach(id => {
        this.$refs[id][0].voiChange(v)
      })
    },
    async handleFusion(data) {
      try {
        this.fusionVisible = false
        this.isFusion = true
        this.rows = 2
        this.cols = 2
        const { ct, pt } = data
        this.loading = true
        this.loadingText = this.$t('trials:lugano:message:loadVolumes')
        // this.resetAnnotation = true
        // console.log(cornerstoneTools.annotation.state.getAllAnnotations(),'cornerstoneTools.annotation.state')
        // cornerstoneTools.annotation.state.removeAllAnnotations()
        this.renderedTaskIds = []
        if (this.verifyFusionData(ct, pt)) {
          this.loading = false
          this.loadingText = null
          this.$refs[`viewport-0`][0].setSeriesInfo(ct)
          this.$refs[`viewport-1`][0].setSeriesInfo(pt)
          this.$refs[`viewport-2`][0].setSeriesInfo(pt)
          this.$refs[`viewport-3`][0].setSeriesInfo(pt)
          // this.resetAnnotation = false
          return true
        }
        if (!this.fusionSerieId.ct || this.fusionSerieId.ct !== ct.SeriesInstanceUid) {
          this.fusionSerieId.ct = ct.SeriesInstanceUid
        }
        if (!this.fusionSerieId.pt || this.fusionSerieId.pt !== pt.SeriesInstanceUid) {
          this.fusionSerieId.pt = pt.SeriesInstanceUid
        }
        await this.getVolume(pt)
        await this.getVolume(ct)
        await this.getVolume(pt, true)
        this.loading = false
        this.loadingText = null
        const ctData = {
          data: ct,
          volumeId: this.volumeData[ct.SeriesInstanceUid].volumeId
        }
        const ptData = {
          data: pt,
          volumeId: this.volumeData[pt.SeriesInstanceUid].volumeId,
          volume: this.volumeData[pt.SeriesInstanceUid].volume
        }
        const fusionData = {
          ct,
          data: pt,
          volumeId: this.volumeData[pt.SeriesInstanceUid].volumeId,
          ctVolumeId: this.volumeData[ct.SeriesInstanceUid].volumeId,
          ptVolumeId: this.volumeData[pt.SeriesInstanceUid].volumeId,
          fusionVolumeId: this.volumeData[`fusion_${pt.SeriesInstanceUid}`].volumeId
        }
        this.$refs[`viewport-0`][0].setSeriesInfo(ct)
        this.$refs[`viewport-1`][0].setSeriesInfo(pt)
        this.$refs[`viewport-2`][0].setSeriesInfo(pt)
        this.$refs[`viewport-3`][0].setSeriesInfo(pt)

        this.$refs[`viewport-fusion-0`][0].setSeriesInfo(ctData)
        this.$refs[`viewport-fusion-1`][0].setSeriesInfo(ptData, { colorMap: true })
        this.$refs[`viewport-fusion-2`][0].setSeriesInfo(fusionData, { isFusion: true, colorMap: true })
        this.$refs[`viewport-fusion-3`][0].setSeriesInfo(ptData, { isMip: true, colorMap: true })
        // this.resetAnnotation = false
        this.$nextTick(() => {
          this.$refs[`colorMap`].init()
        })
      } catch (err) {
        console.log(err)
        this.loading = false
        this.loadingText = null
      }
    },
    verifyFusionData(ct, pt) {
      if (this.fusionSerieId.ct === ct.SeriesInstanceUid && this.fusionSerieId.pt === pt.SeriesInstanceUid && cache.getVolume(this.volumeData[ct.SeriesInstanceUid].volumeId) && cache.getVolume(this.volumeData[pt.SeriesInstanceUid].volumeId) && cache.getVolume(this.volumeData[`fusion_${pt.SeriesInstanceUid}`].volumeId)) {
        return true
      }
      return false
    },
    async getVolume(serie, isFusion = false) {
      return new Promise(async res => {
        let volumeId = null; let volume = null
        const key = isFusion ? `fusion_${serie.SeriesInstanceUid}` : serie.SeriesInstanceUid
        if (!this.volumeData[key] || !cache.getVolume(this.volumeData[key].volumeId)) {
          if (serie.Modality === 'PT' && !isFusion) {
            serie.ImageIds.forEach(async id => {
              const imageLoadObject = cache.getImage(id)
              if (imageLoadObject) {
                await new Promise(res => {
                  cache.removeImageLoadObject(id, { force: true }) // 从缓存中删除
                  res()
                })
              }
            })
          }
          await this.$refs[`viewport-fusion-0`][0].createImageIdsAndCacheMetaData(serie)
          volumeId = `${isFusion ? 'fusion' : serie.Modality}Volume` + ':' + csUtils.uuidv4()
          volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: serie.ImageIds })
          volume.load()
          this.volumeData[key] = {}
          this.volumeData[key].volumeId = volumeId
          this.volumeData[key].volume = volume
        } else {
          volumeId = this.volumeData[key].volumeId
          volume = this.volumeData[key].volume
        }

        res({ volumeId, volume })
      })
    },
    upperRangeChange(upper) {
      this.$refs.colorMap.upper = upper
      this.$refs.colorMap.upperRangeChange(upper)
    },
    openFusion() {
      this.fusionVisible = true
    },
    closeFusion() {
      this.fusionVisible = false
    },
    getTrialCriterion() {
      getCriterionReadingInfo({
        TrialId: this.$route.query.trialId,
        TrialReadingCriterionId: this.$route.query.TrialReadingCriterionId
      })
        .then((res) => {
          this.trialCriterion = res.Result
        })
        .catch(() => {})
    },
    async uploadScreenshots(fileName, file) {
      try {
        file = this.convertBase64ToBlob(file)
        const trialId = this.$route.query.trialId
        const taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
        const subjectId = taskInfo.SubjectId
        const result = await this.OSSclient.put(`/${trialId}/Read/${subjectId}/Visit/${fileName}.png`, file)
        return { isSuccess: true, result: result }
      } catch (e) {
        console.log(e)
        return { isSuccess: false, result: e }
      }
    },
    convertBase64ToBlob(imageEditorBase64) {
      const base64Arr = imageEditorBase64.split(',')
      let imgtype = ''
      let base64String = ''
      if (base64Arr.length > 1) {
        base64String = base64Arr[1]
        imgtype = base64Arr[0].substring(
          base64Arr[0].indexOf(':') + 1,
          base64Arr[0].indexOf(';')
        )
      }
      const bytes = atob(base64String)
      const bytesCode = new ArrayBuffer(bytes.length)
      const byteArray = new Uint8Array(bytesCode)
      for (let i = 0; i < bytes.length; i++) {
        byteArray[i] = bytes.charCodeAt(i)
      }
      return new Blob([bytesCode], { type: imgtype })
    },
    openUploadImage(status) {
      const idx = this.visitTaskList.findIndex(i => i.IsCurrentTask)
      if (idx > -1) {
        this.taskId = this.visitTaskList[idx].VisitTaskId
      }
      this.uploadSubjectCode = localStorage.getItem("subjectCode")
      this.uploadSubjectId = localStorage.getItem("subjectId")
      this.uploadTrialCriterion = this.trialCriterion
      this.uploadStatus = status
      this[`${status}ImageVisible`] = true
    },
  },
  beforeDestroy() {
    DicomEvent.$off('isCanActiveNoneDicomTool')
    DicomEvent.$off('removeNoneDicomMeasureData')
    DicomEvent.$off('addNoneDicomMeasureData')
    if (this.saveCustomAnnotationTimer) {
      clearTimeout(this.saveCustomAnnotationTimer)
      this.saveCustomAnnotationTimer = null
    }
    workSpeedclose(true)
  }
}
</script>
<style lang="scss" scoped>
  .read-page-container {
    box-sizing: border-box;
    height: 100%;
    display: flex;
    ::-webkit-scrollbar {
      width: 5px;
      height: 5px;
    }
    ::-webkit-scrollbar-thumb {
      border-radius: 10px;
      background: #d0d0d0;
    }
    .left-panel {
      display: flex;
      width: 200px;
      border: 1px solid #727272;
      color: #fff;
      user-select: none;
      ::-webkit-scrollbar {
        width: 3px;
        height: 3px;
      }
      ::-webkit-scrollbar-thumb {
        border-radius: 10px;
        background: #d0d0d0;
      }
      .task-container {
        position: relative;
        width: 25px;
        overflow-y: auto;
      }
      .task-info {
        position: absolute;
        top: 5px;
        right: 20px;
        transform-origin: right top;
        transform: rotate(-90deg);
        display: flex;
        .task-item {
          margin-left: 10px;
          white-space: nowrap;
          padding: 0px  4px;
          border: 1px solid #999999;
          border-bottom:none ;
          text-align: center;
          background-color: #4e4e4e;
          color: #d5d5d5;
          cursor: pointer;
        }
        .task-item-active {
          background-color: #607d8b;
          border: 1px solid #607d8b;
        }
      }
      .study-info {
        width: 170px;
        border-left: 1px solid #727272;
      }
    }
    .middle-panel {
      flex: 1;
      border: 1px solid #727272;
      margin: 0 5px;
      user-select: 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;
            .el-dropdown-link {
              .svg-icon {
                color: #ddd;
                font-size: 20px;
              }
            }
          }
          .tool-item-active {
            background-color: #607d8b;
          }
          .tool-disabled {
            cursor: not-allowed;
          }
          .tool-frame{
            display: flex;
            flex-direction: row;
            justify-content: flex-start;
            align-items: center;
            // margin-right: 20px;
            padding: 1px;
            margin: 0 5px;
            border: 1px solid #404040;
            .icon{
              padding: 5px;
              border-right: 1px solid #404040;
              cursor: pointer;
              text-align: center;
              .svg-icon{
                font-size:20px;
                color:#ddd;
              }
            }
            .select-wrapper{
              width: 60px;
              background-color: black;
              color: #ddd;
              border: none;
              font-size: 13px;
              outline: none;
            }
            .text{
              position: relative;
              font-size: 12px;
              margin-top: 5px;
              color: #d0d0d0;
              display: none;
            }
          }
          // .icon:hover{
          //   background-color: #607d8b;
          // }
          .dropdown {
            position: relative;
            display: inline-block;
            .text{
              text-align: center;
            }
          }
          .dropdown-content {
            display: none;
            position: absolute;
            background-color: #383838;
            color: #fff;
            box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
            z-index: 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;
            }
          }
          .layout-content-ul li:hover{
            background-color: #727272;
          }
          .layout-content ul li{
            border-top:1px solid #ddd;
            border-left:1px solid #ddd;
          }
          .layout_flex_row {
            display: flex;
            justify-content: space-between;
            flex-direction: row;
            align-items: center;
            text-align: center;
            margin-bottom: 2px;
          }
          .layout_flex_column{
            display: flex;
            justify-content: space-between;
            flex-direction: column;
            align-items: center;
            margin-bottom: 2px;
          }
          .layout_box_1_1{
            flex:1;
            line-height: 30px;
            font-size: 12px;
            text-align: center;
            border-bottom:1px solid #ddd;
            border-right:1px solid #ddd;
          }
          .layout_box_1_2{
            flex:1;
            line-height: 15px;
            font-size: 10px;
            text-align: center;
            border-bottom:1px solid #ddd;
            border-right:1px solid #ddd;
          }
          .divider{
            display: block;
            height: 1px;
            width: 100%;
            margin: 10px 0;
          }
          .el-divider__text{
            padding: 0 10px;
            font-size: 12px;
            width: 80px;
            background-color: #383838;
            color: #fff;
          }
        }
        .content-wrapper {
          flex: 1;
          height: calc(100% - 50px);
          display: flex;
          flex-direction: row;
        }
        .viewports-wrapper {
          flex: 1;
          .grid-container {
            display: grid;
            height: 100%;
            width: 100%;
            position: relative;
          }
          .viewports-box {
            display: grid;
            position: absolute;
            height: 100%;
            width: 100%;
            top: 0;
            left: 0;
            bottom: 0;
            right: 0;
            z-index: 9;
          }
          .viewports-box-down{
            z-index: 1;
          }
          .grid-cell {
            border: 1px dashed #ccc;;
            display: flex;
            align-items: center;
            justify-content: center;
            z-index: 1;
          }
          .cell_active {
            border-color: #fafa00!important;
          }
          .cell-full-screen {
            grid-column: 1 / -1;
            grid-row: 1 / -1;
            z-index: 9;
          }
        }
        .form-wrapper {
          width: 400px;
          height: 100%;
          border: 1px solid #727272;
          user-select: none;
        }
      }
    }

    .personal_config {
      ::v-deep .el-tabs__content{
        height: 450px;
        overflow-y: auto;
      }
    }
    ::v-deep .manuals-dialog-container{
      margin-top: 50px !important;
      width:75%;
      height:80%;
      .el-dialog__body{
        padding: 10px;
        height: calc(100% - 50px) !important;
      }
      .el-dialog__header{
        position: relative;
      }
    }
    ::v-deep .manuals-full-dialog-container{
      .el-dialog__body{
        padding: 10px;
        height: calc(100% - 50px) !important;
      }
      .el-dialog__header{
        position: relative;
      }
    }
    ::v-deep .cd-dialog-container{
      background: #fff !important;
      margin-top: 50px !important;
      width: 75%;
      height: 80%;
      .el-dialog__body{
        padding: 20px 20px 0 20px;
        height: calc(100% - 70px);
      }
      .el-dialog__header{
        position: relative;
      }
    }

    ::v-deep .cd-full-dialog-container{
      background: #fff !important;
      .el-dialog__body{
        padding: 10px;
        height: calc(100% - 50px) !important;
      }
      .el-dialog__header{
        position: relative;
      }
    }
    ::v-deep .el-dropdown-menu{
      .el-dropdown-menu__item {
        padding: 0 5px;
      }
      .layout_flex_row {
        display: flex;
        justify-content: space-between;
        flex-direction: row;
        align-items: center;
        width: 40px;
        align-items: center;
        text-align: center;
      }
      .layout_flex_column{
        display: flex;
        justify-content: space-between;
        flex-direction: column;
        align-items: center;
      }
      .layout_box_1_1{
        flex:1;
        line-height: 30px;
        font-size: 12px;
        text-align: center;
        // border-bottom:1px solid #ddd;
        // border-right:1px solid #ddd;
      }
      .layout_box_1_2{
        flex:1;
        line-height: 15px;
        font-size: 10px;
        text-align: center;
        // border-bottom:1px solid #ddd;
        // border-right:1px solid #ddd;
      }
    }
  }

</style>
