<template>
  <div class="none-dicom-viewer">
    <!-- tools -->
    <div class="tools-wrapper">
      <div class="tools-left">
        <!-- 布局 -->
        <div class="tool-item" :title="$t('trials:reading:button:layout')">
          <el-dropdown @command="handleCommand">
            <span class="el-dropdown-link">
              <svg-icon icon-class="layout" class="svg-icon" /><i class="el-icon-arrow-down el-icon--right" />
            </span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item command="1*1">1*1</el-dropdown-item>
              <el-dropdown-item command="1*2">1*2</el-dropdown-item>
              <el-dropdown-item command="2*2">2*2</el-dropdown-item>
            </el-dropdown-menu>
          </el-dropdown>
        </div>
        <!-- 缩放 -->
        <div :class="['tool-item', activeTool === 'Zoom' ? 'tool-item-active' : '']"
          :title="$t('trials:reading:button:zoom')" @click.prevent="setToolActive('Zoom')">
          <svg-icon icon-class="magnifier" class="svg-icon" />
        </div>
        <!-- 移动 -->
        <div :class="['tool-item', activeTool === 'Pan' ? 'tool-item-active' : '']"
          :title="$t('trials:reading:button:move')" @click.prevent="setToolActive('Pan')">
          <svg-icon icon-class="move" class="svg-icon" />
        </div>
        <!-- 旋转 -->
        <div :class="['tool-item', activeTool === 'PlanarRotate' ? 'tool-item-active' : '']"
          :title="$t('trials:reading:button:rotate')" @click.prevent="setToolActive('PlanarRotate')">
          <svg-icon icon-class="rotate" class="svg-icon" />
        </div>
        <!-- 查看关键序列 -->
        <el-popover v-model="keySeriesPopoverVisible" placement="bottom" trigger="click"
          popper-class="key-series-popper" @show="showKeySeriesPanel">
          <ul class="key-series-list">
            <li v-if="keyTaskInfo && keyTaskInfo.TaskBlindName" class="key-series-header">
              <div class="key-series-header-top">
                <div class="key-series-header-title">
                  <span class="key-series-header-dot"></span>
                  <div class="key-series-task-name" :title="keyTaskInfo.TaskBlindName">
                    {{ keyTaskInfo.TaskBlindName }}
                  </div>
                </div>
              </div>
            </li>
            <li v-if="keySeriesLoading" class="key-series-empty">
              <i class="el-icon-loading"></i>
            </li>
            <li v-else-if="keySeries.length === 0" class="key-series-empty">
              {{ $t('trials:reading:keyImage:noData') }}
            </li>
            <li v-for="(kf, idx) in keySeries" :key="idx" class="key-series-item"
              @click.stop.prevent="jumpToKeySeries(kf)">
              <div class="key-series-img">
                <img v-if="kf.PicturePath" :src="`${OSSclientConfig.basePath}${kf.PicturePath}`" />
                <svg-icon v-else icon-class="image" class="svg-icon default-icon" />
              </div>
              <div class="key-series-info">
                <div class="key-series-meta" v-if="kf.MarkName">
                  <div class="key-series-label">{{ $t('trials:reading:keySeries:annotationName') }}</div>
                  <div class="key-series-uid" :title="kf.MarkName">
                    {{ kf.MarkName }}
                  </div>
                </div>
                <div class="key-series-meta">
                  <div class="key-series-label">{{ $t('trials:reading:keySeries:fileName') }}</div>
                  <div class="key-series-uid" :title="kf.FileName">
                    {{ kf.FileName }}
                  </div>
                </div>
              </div>
              <div class="key-series-star">
                <svg-icon icon-class="star" class="svg-icon" />
              </div>
            </li>
          </ul>
          <div slot="reference" class="tool-item">
            <div class="icon" :title="$t('trials:reading:button:keyImage')">
              <!-- <svg-icon icon-class="star" class="svg-icon" /> -->
              <i class="el-icon-star-off svg-icon"></i>
            </div>
          </div>
        </el-popover>
        <div v-for="tool in tools" :key="tool.toolName"
          :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === tool.toolName ? 'tool-item-active' : '']"
          :style="{ cursor: tool.isDisabled ? 'not-allowed' : 'pointer' }"
          :title="tool.disabledReason ? tool.disabledReason : $t(`${tool.i18nKey}`)"
          @click.prevent="setAnnotateToolActive(tool.toolName)">
          <svg-icon :icon-class="tool.icon" class="svg-icon" />
        </div>
        <!-- <div
          :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'SplineROITool' ? 'tool-item-active' : '']"
          :title="$t('trials:reading:button:SplineROITool')"
          @click.prevent="setAnnotateToolActive('SplineROITool')"
        >
          <svg-icon icon-class="polygon" class="svg-icon" />
        </div> -->
        <!--readingTaskState === 2 ? 'tool-disabled' : '',-->
        <div :class="['tool-item', activeTool === 'Eraser' ? 'tool-item-active' : '']"
          :title="$t('trials:dicom-show:Eraser')" @click.prevent="setAnnotateToolActive('Eraser')">
          <svg-icon icon-class="clear" class="svg-icon" />
        </div>
        <!--比例尺-->
        <div
          :class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '', activeTool === 'Lengthscale' ? 'tool-item-active' : '']"
          :title="$t('trials:nondicom-show:scale')" @click.prevent="setAnnotateToolActive('Lengthscale')">
          <svg-icon icon-class="lengthscale" class="svg-icon" />
        </div>

        <!-- 截图 -->
        <div class="tool-item" :title="$t('trials:reading:button:screenShot')" @click.prevent="saveImage">
          <svg-icon icon-class="image" class="svg-icon" />
        </div>
        <!-- 重置 -->
        <div class="tool-item" :title="$t('trials:reading:button:reset')" @click.prevent="resetViewport">
          <svg-icon icon-class="refresh" class="svg-icon" />
        </div>
        <!-- 更多:class="['tool-item', readingTaskState === 2 ? 'tool-disabled' : '']" -->
        <div v-if="criterionType === 0 && customizeStandardsNoneDicom.length > 0" :title="$t('trials:reading:button:more')"
          :class="['tool-item']" @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">
              <!--v-if="readingTaskState < 2"-->
              <ul class="customize-standards-list">
                <li v-for="i in customizeStandardsNoneDicom" :key="i.toolName" style="text-align:left;">
                  <a href="#" @click.prevent="setAnnotateToolActive(i.toolName)">
                    <svg-icon :icon-class="i.icon" class="svg-icon" style="margin-right: 5px;font-size: 15px;" />
                    {{ $t(i.i18nKey) }}
                  </a>
                </li>
              </ul>
            </div>
          </div>
        </div>
        <div class="tool-item" :title="$t('trials:reading:button:upload')"
          v-if="trialCriterion.ImageUploadEnum > 0 && readingTaskState < 2" v-hasPermi="['role:ir']">
          <div class="tool-wrapper">
            <div class="icon" @click.prevent="openUploadImage('upload')">
              <i class="el-icon-upload2 svg-icon" />
            </div>
          </div>
        </div>
        <div v-if="trialCriterion.ImageDownloadEnum > 0" v-hasPermi="[
          'role:ir',
          'role:mim',
          'role:mc',
          'role:pm',
          'role:apm',
          'role:ea',
          'role:qa',
        ]" class="tool-item" :title="$t('trials:reading:button:download')">
          <div class="tool-wrapper">
            <div class="icon" @click.prevent="openUploadImage('download')">
              <i class="el-icon-download svg-icon" />
            </div>
          </div>
        </div>
      </div>

      <div style="display: flex;">
        <!-- 手册 -->
        <div class="tool-item" :title="$t('trials:reading:button:handbooks')"
          v-if="taskInfo && (taskInfo.ExistsManual || taskInfo.IsHaveKeyFile) && readingTaskState < 2"
          @click.prevent="previewManuals">
          <svg-icon icon-class="constitution" class="svg-icon" />
        </div>
        <!-- 个性化配置 -->
        <div class="tool-item" :title="$t('trials:reading:button:customCfg')" @click.prevent="previewConfig">
          <svg-icon icon-class="individuation" class="svg-icon" />
        </div>
      </div>
    </div>
    <!-- viewports -->
    <div class="viewports-wrapper" v-loading="loading" ref="viewports-wrapper">
      <div ref="container" class="grid-container" :style="gridStyle">
        <div v-for="(v, index) in viewportInfos" :ref="`grid-cell-${index}`" :key="index" :style="getCellStyle(index)"
          :class="['grid-cell', index === activeCanvasIndex ? 'cell_active' : '', index === fullScreenIndex ? 'cell-full-screen' : '']"
          @dblclick="toggleFullScreen($event, index)" @click="activeCanvas(index)"
          @mouseup="sliderMouseup($event, index)" @mousemove="sliderMousemove($event, index)"
          @mouseleave="sliderMouseleave($event, index)">
          <div v-show="imageType.includes(v.fileType)" :ref="`canvas-${index}`" class="content"
            @mouseup="contentMouseup($event, index)">
            <div class="left-top-text">
              <div v-if="v.taskInfo.IsExistsClinicalData" class="cd-info"
                :title="$t('trials:reading:button:clinicalData')">
                <svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
                  @click.stop="viewCD(v.taskInfo.VisitTaskId)" />
              </div>
              <h2 class="subject-info">
                {{ taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo ? taskInfo.SubjectCode + ' ' + v.taskInfo.TaskBlindName : v.taskInfo.TaskBlindName }}
              </h2>
              <div v-if="v.currentFileName">{{ v.currentFileName }}</div>
            </div>
            <div v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo" class="top-center-tool">
              <div class="toggle-visit-container">
                <div class="arrw_icon"
                  :style="{ cursor: v.taskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
                  @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, -1, v.index)"
                  @dblclick.stop="preventDefault($event)">
                  <i class="el-icon-caret-left" />
                </div>
                <div class="arrow_text">
                  {{ v.taskInfo.TaskBlindName }}
                </div>
                <div class="arrw_icon"
                  :style="{ cursor: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
                  @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, 1, v.index)"
                  @dblclick.stop="preventDefault($event)">
                  <i class="el-icon-caret-right" />
                </div>
              </div>
            </div>
            <div :ref="`sliderBox-${index}`" class="right-slider-box" @click.stop="clickSlider($event, index)">
              <div :style="{ top: v.height + '%' }" class="slider" @click.stop.prevent="() => { return }"
                @mousedown.stop="sliderMousedown($event, index)" />
            </div>
          </div>
          <div v-if="v.fileType === 'application/pdf' && fullScreenIndex === null" class="content flex_col">
            <div class="content-top" style="height: 50px;">
              <div class="left-top-text">
                <div v-if="v.taskInfo.IsExistsClinicalData" class="cd-info"
                  :title="$t('trials:reading:button:clinicalData')">
                  <svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
                    @click.stop="viewCD(v.taskInfo.VisitTaskId)" />
                </div>
                <h2 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo" class="subject-info">
                  {{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
                </h2>
                <div v-if="v.currentFileName">{{ v.currentFileName }}</div>
              </div>
              <div v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo" class="top-center-tool">
                <div class="toggle-visit-container">
                  <div class="arrw_icon"
                    :style="{ cursor: v.taskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
                    @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, -1, v.index)"
                    @dblclick.stop="preventDefault($event)">
                    <i class="el-icon-caret-left" />
                  </div>
                  <div class="arrow_text">
                    {{ v.taskInfo.TaskBlindName }}
                  </div>
                  <div class="arrw_icon"
                    :style="{ cursor: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
                    @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, 1, v.index)"
                    @dblclick.stop="preventDefault($event)">
                    <i class="el-icon-caret-right" />
                  </div>
                </div>
              </div>
            </div>
            <div class="content-main" style="flex: 1;">
              <iframe v-if="v.currentFilePath" :ref="`iframe-${index}`"
                :src="`/static/pdfjs/web/viewer.html?file=${OSSclientConfig.basePath}${v.currentFilePath}?index=${index}`"
                width="100%" height="100%" frameborder="0" crossorigin="anonymous" />
            </div>

          </div>

          <div v-if="v.fileType.includes('mp4')" class="content flex_col">
            <div class="content-top" style="height: 50px;">
              <div class="left-top-text">
                <div v-if="v.taskInfo.IsExistsClinicalData" class="cd-info"
                  :title="$t('trials:reading:button:clinicalData')">
                  <svg-icon style="cursor: pointer;" icon-class="documentation" class="svg-icon"
                    @click.stop="viewCD(v.taskInfo.VisitTaskId)" />
                </div>
                <h2 v-if="taskInfo && taskInfo.IsReadingShowSubjectInfo && v.taskInfo" class="subject-info">
                  {{ `${taskInfo.SubjectCode} ${v.taskInfo.TaskBlindName} ` }}
                </h2>
                <div v-if="v.currentFileName">{{ v.currentFileName }}</div>
              </div>
              <div v-if="taskInfo && taskInfo.IsReadingTaskViewInOrder === 1 && v.taskInfo" class="top-center-tool">
                <div class="toggle-visit-container">
                  <div class="arrw_icon"
                    :style="{ cursor: v.taskInfo.VisitTaskNum !== 0 ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum !== 0 ? '#fff' : '#6b6b6b' }"
                    @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, -1, v.index)"
                    @dblclick.stop="preventDefault($event)">
                    <i class="el-icon-caret-left" />
                  </div>
                  <div class="arrow_text">
                    {{ v.taskInfo.TaskBlindName }}
                  </div>
                  <div class="arrw_icon"
                    :style="{ cursor: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? 'pointer' : 'not-allowed', color: v.taskInfo.VisitTaskNum < taskInfo.VisitNum ? '#fff' : '#6b6b6b' }"
                    @click.stop.prevent="toggleTask($event, v.taskInfo.VisitTaskNum, 1, v.index)"
                    @dblclick.stop="preventDefault($event)">
                    <i class="el-icon-caret-right" />
                  </div>
                </div>
              </div>
            </div>
            <div class="content-main" :ref="`video-content-main-${index}`" style="flex: 1;">
              <video v-if="v.currentFilePath" :ref="`videovideo-${index}`"
                :src="`${OSSclientConfig.basePath}${v.currentFilePath}`" crossorigin="anonymous" width="100%"
                height="100%" autoplay controls controlsList="nodownload"></video>
            </div>

          </div>

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

    <el-dialog :title="$t('trials:noneDicom:message:msg2')" :visible.sync="dialogVisible" :close-on-click-modal="false"
      :close-on-press-escape="false" :show-close="false" width="400px">
      <el-form ref="lengthForm" :model="form" :rules="rules">
        <el-form-item label="" prop="length" v-show="false">
          <el-input v-model="form.length" type="number">
            <template slot="append">mm</template>
          </el-input>
        </el-form-item>
        <el-form-item label="" prop="length">
          <el-input v-model="form.length" type="number">
            <template slot="append">mm</template>
          </el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button type="primary" @click="saveForm">{{ $t('common:button:save') }}</el-button>
      </span>
    </el-dialog>

    <el-dialog v-if="personalConfigDialog.visible" :visible.sync="personalConfigDialog.visible"
      :close-on-click-modal="false" :title="personalConfigDialog.title" width="600px">
      <!-- <Others /> -->
      <el-tabs v-model="activeName" class="personal_config">
        <!-- 热键 -->
        <el-tab-pane :label="$t('trials:reading:tab:hotkeys')" name="1">
          <Hotkeys v-if="activeName === '1'" :reading-tool="1" @reset="resetHotkeyList" />
        </el-tab-pane>
        <!-- 其他 -->
        <el-tab-pane :label="$t('trials:reading:tab:others')" name="2">
          <Others v-if="activeName === '2'" :imageToolType="2" />
        </el-tab-pane>
      </el-tabs>
    </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" />
    <!-- 手册 -->
    <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="manualsDialog.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" :justKeyDoc="manualsDialog.justKeyDoc" />
        <div slot="footer" style="text-align:right;" v-if="openManuals && !ManualsClose">
          <!-- 确认 -->
          <el-button type="primary" size="mini" @click="handleSubmitKeyDoc">
            {{ $t('common:button:confirm') }}</el-button>
        </div>
      </div>
    </el-dialog>
  </div>
</template>
<script>
import { addNoneDicomMark, deleteTrialFileType, getCriterionReadingInfo, setReadKeyFile } from '@/api/trials'
import { getNoneDicomMarkList } from '@/api/reading'
import { getDoctorShortcutKey } from '@/api/user'
import html2canvas from 'html2canvas'
import {
  RenderingEngine,
  Enums,
  imageLoader,
  metaData,
  getRenderingEngine,
  eventTarget,
  utilities as csUtils
  // getEnabledElementByIds
} from '@cornerstonejs/core'

import * as cornerstoneTools from '@cornerstonejs/tools'
import initLibraries from '@/views/trials/trials-panel/reading/dicoms/components/Fusion/js/initLibraries'
import hardcodedMetaDataProvider from './../js/hardcodedMetaDataProvider'
import registerWebImageLoader from './../js/registerWebImageLoader'
import { mapGetters } from 'vuex'
import store from '@/store'
import Hotkeys from '@/views/trials/trials-panel/reading/dicoms/components/Hotkeys'
import Others from '@/views/trials/trials-panel/reading/dicoms/components/Others'
import Manuals from '@/views/trials/trials-panel/reading/dicoms/components/Manuals'
const { ViewportType } = Enums
const renderingEngineId = 'myRenderingEngine'
import LengthscaleTool from "../tools/LengthscaleTool"
import { getCustomizeStandardsNoneDicomTools, config } from '@/views/trials/trials-panel/reading/dicoms3D/components/toolConfig'
import uploadDicomAndNonedicom from '@/components/uploadDicomAndNonedicom'
import downloadDicomAndNonedicom from '@/components/downloadDicomAndNonedicom'
const {
  ToolGroupManager,
  Enums: csToolsEnums,
  StackScrollTool,
  PanTool,
  ZoomTool,
  PlanarRotateTool,
  ArrowAnnotateTool,
  RectangleROITool,
  PlanarFreehandROITool,
  SplineROITool,
  EraserTool,
  LengthTool,
  EllipticalROITool,
  CircleROITool,
  AngleTool,
  BidirectionalTool,
  // cursors
} = cornerstoneTools
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'
  }
}
cornerstoneTools.annotation.config.style.setDefaultToolStyles(newStyles)
const { MouseBindings, Events: toolsEvents } = csToolsEnums
export default {
  name: 'ImageViewer',
  components: {
    Hotkeys,
    Others,
    downloadDicomAndNonedicom,
    uploadDicomAndNonedicom,
    Manuals
  },
  props: {
    relatedStudyInfo: {
      type: Object,
      default() {
        return {}
      }
    },
    psArr: {
      type: Array,
      default() {
        return []
      }
    },
    ecrf: {
      type: Object,
      default() {
        return {}
      }
    }
  },
  data() {
    return {
      rows: 1,
      cols: 1,
      fullScreenIndex: null,
      imageIds: [],
      activeCanvasIndex: 0,
      activeCanvasFileType: '',
      layout: '1*2',
      cellsMax: 4,
      viewportInfos: [],
      taskInfo: {},
      activeTool: '',
      readingTaskState: 2,
      renderHistoryAnnotationTaskIds: [],
      imageType: ['image/jpeg', 'image/jpg', 'image/bmp', 'image/png'],
      digitPlaces: 2,
      dialogVisible: false,
      personalConfigDialog: { visible: false, title: this.$t('trials:reading:button:customCfg') }, // 个性化配置
      form: {
        length: null,
        annotationObj: {}
      },
      rules: {
        length: [
          { required: true, message: this.$t('common:ruleMessage:specify'), trigger: 'blur' },
          { pattern: /^\d+$/, message: this.$t('trials:noneDicom:message:msg3'), trigger: ['blur', 'change'] }
        ]
      },

      customizeStandardsNoneDicom: [],
      tools: [],
      criterionType: null,


      // 上传
      downloadImageVisible: false,
      uploadImageVisible: false,
      uploadSubjectId: null,
      uploadSubjectCode: null,
      uploadTrialCriterion: {},
      uploadStatus: 'upload',
      taskId: '',
      isReadingTaskViewInOrder: null,
      trialCriterion: {},
      saveCustomAnnotationTimer: null,
      curOperation: {
        type: '',
        annotation: null
      },
      loading: false,
      manualsDialog: { visible: false, isFullscreen: false, justKeyDoc: false },
      trialId: null,

      ManualsClose: false,
      activeName: '1',
      hotKeyList: [],
      isShowAnnotations: true,
      keySeries: [],
      keyTaskInfo: null,
      keySeriesLoading: false,
      keySeriesPopoverVisible: false
    }
  },
  computed: {
    gridStyle() {
      return {
        display: 'grid',
        gridTemplateRows: `repeat(${this.rows}, 1fr)`,
        gridTemplateColumns: `repeat(${this.cols}, 1fr)`,
        height: '100%',
        width: '100%'
      }
    },
    cellStyle() {
      return {
        border: '1px dashed #ccc',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center'
      }
    },
    cells() {
      return Array(this.rows * this.cols).fill(0)
    },
    ...mapGetters(['lastViewportTaskId', 'currentTaskState']),
    openManuals() {
      return !this.taskInfo.IsReadKeyFile && this.taskInfo.IsHaveKeyFile
    }
  },
  watch: {
    openManuals: {
      handler() {
        if (this.openManuals) this.previewManuals(true)
      },
      immediate: true
    },
    relatedStudyInfo: {
      immediate: true,
      handler(obj) {
        if (!obj || Object.keys(obj).length === 0) return
        this.updateViewportInfos(0, obj)
      }
    },
    currentTaskState: {
      immediate: true,
      handler(state) {
        if (state === 2) {
          this.readingTaskState = 2
          // 设置标记锁定
          const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
          annotations.map(annotation => {
            cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
          })
          this.setToolsPassive()
        }
      }
    }
  },
  mounted() {
    this.trialId = this.$route.query.trialId
    this.taskInfo = JSON.parse(localStorage.getItem('taskInfo'))
    this.readingTaskState = this.taskInfo.ReadingTaskState
    this.criterionType = this.taskInfo.CriterionType
    if (this.criterionType === 0) {
      this.tools = getCustomizeStandardsNoneDicomTools(this.taskInfo.ReadingToolList)
      const toolNames = this.tools.map(i => i.toolName)
      this.customizeStandardsNoneDicom = config.customizeStandardsNoneDicom.filter(item => !toolNames.includes(item.toolName))
    } else {
      this.tools = config.customizeStandardsNoneDicom
    }
    if (!this.taskInfo.IsBaseLine && this.taskInfo.IsReadingTaskViewInOrder !== 0) {
      this.rows = 1
      this.cols = 2
      this.activeCanvasIndex = 1
    }
    this.viewportInfos = Array.from({ length: this.cellsMax }, (_, index) => ({
      index: index,
      taskInfo: '',
      studyId: '',
      currentImageIdIndex: 0,
      viewportId: `canvas-${index}`,
      fileType: '',
      currentFileName: '',
      currentFilePath: '',
      imageIds: [],
      oldB: null,
      oldM: null,
      isMove: false,
      height: 0
    }))
    const digitPlaces = Number(localStorage.getItem('digitPlaces'))
    this.digitPlaces = digitPlaces === -1 ? this.digitPlaces : digitPlaces
    this.initLoader()
    window.addEventListener('message', this.handleIframeMessage)
    this.getTrialCriterion()
    this.$refs['viewports-wrapper'].addEventListener('wheel', (e) => {
      this.setToolsPassive()
    });
    this.getHotKeys()
  },
  beforeDestroy() {
    window.removeEventListener('message', this.handleIframeMessage)
  },
  methods: {
    async handleSubmitKeyDoc() {
      try {
        let data = {
          TrialCriterionId: this.$router.currentRoute.query.TrialReadingCriterionId,
        }
        let res = await setReadKeyFile(data)
        if (res.IsSuccess) {
          this.manualsDialog.visible = false
          this.ManualsClose = true
        }
      } catch (err) {
        console.log(err)
      }
    },
    // 手册
    previewManuals(justKeyDoc = false) {
      this.manualsDialog.isFullscreen = false
      this.manualsDialog.visible = true
      this.manualsDialog.justKeyDoc = justKeyDoc
    },
    getTrialCriterion() {
      getCriterionReadingInfo({
        TrialId: this.$route.query.trialId,
        TrialReadingCriterionId: this.$route.query.TrialReadingCriterionId
      })
        .then((res) => {
          this.trialCriterion = res.Result
        })
        .catch(() => { })
    },
    openUploadImage(status) {
      this.taskId = this.taskInfo.VisitTaskId
      this.uploadSubjectCode = localStorage.getItem("subjectCode")
      this.uploadSubjectId = localStorage.getItem("subjectId")
      this.uploadTrialCriterion = this.trialCriterion
      this.uploadStatus = status
      this[`${status}ImageVisible`] = true
    },
    showPanel(e) {
      e.currentTarget.firstChild.lastChild.style.display = 'block'
    },
    toolMouseout(e) {
      e.currentTarget.firstChild.lastChild.style.display = 'none'
    },
    async showKeySeriesPanel() {
      this.keySeries = []
      this.keySeriesLoading = true

      try {
        const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
        if (i > -1) {
          this.keyTaskInfo = this.viewportInfos[i].taskInfo
          const visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId
          const res = await getNoneDicomMarkList({ visitTaskId: visitTaskId })
          if (res && res.Result) {
            this.keySeries = res.Result
          }
        }
      } catch (err) {
        console.log(err)
      } finally {
        this.keySeriesLoading = false
      }
    },
    jumpToKeySeries(kf) {
      const visitTaskId = this.keyTaskInfo.VisitTaskId
      this.$emit('selectFile', {
        path: kf.Path,
        studyId: kf.StudyId,
        visitTaskId: visitTaskId
      })
    },
    // 初始化加载器
    async initLoader() {
      registerWebImageLoader(imageLoader)
      await initLibraries()

      let renderingEngine = getRenderingEngine(renderingEngineId)
      if (!renderingEngine) {
        renderingEngine = new RenderingEngine(renderingEngineId)
      }
      const resizeObserver = new ResizeObserver(() => {
        const renderingEngine = getRenderingEngine(renderingEngineId)
        if (renderingEngine) {
          renderingEngine.resize(true, false)
        }
      })
      const element1 = this.$refs['canvas-0'][0]
      const element2 = this.$refs['canvas-1'][0]
      const element3 = this.$refs['canvas-2'][0]
      const element4 = this.$refs['canvas-3'][0]
      const elements = [
        element1,
        element2,
        element3,
        element4
      ]
      elements.forEach((element, i) => {
        element.oncontextmenu = (e) => e.preventDefault()
        resizeObserver.observe(element)
        element.addEventListener('CORNERSTONE_STACK_NEW_IMAGE', this.stackNewImage)
      })
      const viewportInputArray = [
        {
          viewportId: 'canvas-0',
          type: ViewportType.STACK,
          element: element1
        },
        {
          viewportId: 'canvas-1',
          type: ViewportType.STACK,
          element: element2
        },
        {
          viewportId: 'canvas-2',
          type: ViewportType.STACK,
          element: element3
        },
        {
          viewportId: 'canvas-3',
          type: ViewportType.STACK,
          element: element4
        }
      ]
      const viewportIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
      renderingEngine.setViewports(viewportInputArray)
      this.addAnnotationListeners()
      cornerstoneTools.addTool(StackScrollTool)
      cornerstoneTools.addTool(PanTool)
      cornerstoneTools.addTool(ZoomTool)
      cornerstoneTools.addTool(PlanarRotateTool)
      cornerstoneTools.addTool(ArrowAnnotateTool)
      cornerstoneTools.addTool(RectangleROITool)
      cornerstoneTools.addTool(EllipticalROITool)
      cornerstoneTools.addTool(CircleROITool)
      cornerstoneTools.addTool(AngleTool)
      cornerstoneTools.addTool(PlanarFreehandROITool)
      cornerstoneTools.addTool(SplineROITool)
      cornerstoneTools.addTool(EraserTool)
      cornerstoneTools.addTool(LengthTool)
      cornerstoneTools.addTool(LengthscaleTool)
      cornerstoneTools.addTool(BidirectionalTool)
      viewportIds.forEach((viewportId, i) => {
        const toolGroupId = `canvas-${i}`
        const toolGroup = ToolGroupManager.createToolGroup(toolGroupId)
        toolGroup.addViewport(viewportId, renderingEngineId)
        toolGroup.addTool(StackScrollTool.toolName)
        toolGroup.addTool(PanTool.toolName)
        toolGroup.addTool(ZoomTool.toolName)
        toolGroup.addTool(PlanarRotateTool.toolName)
        toolGroup.addTool(ArrowAnnotateTool.toolName, {
          arrowHeadStyle: 'standard',
          // changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
          //   return doneChangingTextCallback(await this.customPrompt())
          // },
          // getTextCallback: async (doneChangingTextCallback) => {
          //   return doneChangingTextCallback(await this.customPrompt())
          // }
          changeTextCallback: async (data, eventData, doneChangingTextCallback) => {
            return doneChangingTextCallback(data.text)
          },
          getTextCallback: async (doneChangingTextCallback) => {
            return doneChangingTextCallback('Annotation')
          }
        })
        toolGroup.addTool(RectangleROITool.toolName, {
          cachedStats: false,
          getTextLines: this.getRectangleROIToolTextLines
        })
        toolGroup.addTool(BidirectionalTool.toolName, {
          // cachedStats: true
          getTextLines: this.getBidirectionalToolTextLines
        })
        toolGroup.addTool(EllipticalROITool.toolName, {
          cachedStats: false,
          getTextLines: this.getEllipticalROIToolTextLines
        })
        toolGroup.addTool(CircleROITool.toolName, {
          cachedStats: false,
          getTextLines: this.getCircleROIToolTextLines
        })
        toolGroup.addTool(AngleTool.toolName, {
          cachedStats: false,
          getTextLines: this.getAngleToolTextLines
        })
        toolGroup.addTool(PlanarFreehandROITool.toolName, {
          allowOpenContours: false,
          cachedStats: false,
          getTextLines: this.getPlanarFreehandROIToolTextLines
        })
        // const splineConfig = toolGroup.getToolConfiguration(
        //   splineToolName,
        //   'spline'
        // )
        toolGroup.addTool(SplineROITool.toolName)

        toolGroup.addTool(EraserTool.toolName)
        toolGroup.addTool(LengthTool.toolName, {
          getTextLines: this.getLengthToolTextLines,
          cachedStats: false
        })
        toolGroup.addTool(LengthscaleTool.toolName, {
          getTextLines: this.getLengthscaleToolTextLines,
          cachedStats: false
        })

        toolGroup.setToolActive(StackScrollTool.toolName, {
          bindings: [{ mouseButton: MouseBindings.Wheel }]
        })
        toolGroup.setToolPassive(PanTool.toolName)
        toolGroup.setToolPassive(ZoomTool.toolName)
        toolGroup.setToolPassive(PlanarRotateTool.toolName)
        if (this.readingTaskState < 2) {
          toolGroup.setToolPassive(ArrowAnnotateTool.toolName)
          toolGroup.setToolPassive(RectangleROITool.toolName)
          toolGroup.setToolPassive(EllipticalROITool.toolName)
          toolGroup.setToolPassive(CircleROITool.toolName)
          toolGroup.setToolPassive(AngleTool.toolName)
          toolGroup.setToolPassive(PlanarFreehandROITool.toolName)
          toolGroup.setToolPassive(SplineROITool.toolName)
          toolGroup.setToolPassive(LengthTool.toolName)
          toolGroup.setToolPassive(LengthscaleTool.toolName)
          toolGroup.setToolPassive(BidirectionalTool.toolName)
        } else {
          toolGroup.setToolEnabled(ArrowAnnotateTool.toolName)
          toolGroup.setToolEnabled(RectangleROITool.toolName)
          toolGroup.setToolEnabled(EllipticalROITool.toolName)
          toolGroup.setToolEnabled(CircleROITool.toolName)
          toolGroup.setToolEnabled(AngleTool.toolName)
          toolGroup.setToolEnabled(PlanarFreehandROITool.toolName)
          toolGroup.setToolEnabled(SplineROITool.toolName)
          toolGroup.setToolEnabled(LengthTool.toolName)
          toolGroup.setToolEnabled(LengthscaleTool.toolName)
          toolGroup.setToolEnabled(BidirectionalTool.toolName)
        }
        toolGroup.setToolPassive(EraserTool.toolName)
      })
    },
    lengthscaleToolDisabled(saved) {
      const viewportIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
      viewportIds.forEach(toolGroupId => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (saved) {
          toolGroup.setToolPassive(LengthscaleTool.toolName)
        } else {
          toolGroup.setToolEnabled(LengthscaleTool.toolName)
        }
      })
    },
    // 加载图片回调
    stackNewImage(e) {
      const { detail } = e
      const i = this.viewportInfos.findIndex(i => i.viewportId === detail.viewportId)
      if (i === -1) return
      this.viewportInfos[i].currentImageIdIndex = detail.imageIdIndex
      const obj = this.viewportInfos[i].fileList[detail.imageIdIndex]
      if (!obj) return
      this.viewportInfos[i].currentFileName = obj.FileName
      this.viewportInfos[i].height = (this.viewportInfos[i].currentImageIdIndex) * 100 / (this.viewportInfos[i].imageIds.length - 1)
      const path = detail.imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, path: path })
      this.renderHistoryAnnotations(this.viewportInfos[i].taskInfo)
    },
    renderHistoryAnnotations(obj) {
      if (this.renderHistoryAnnotationTaskIds.includes(obj.VisitTaskId)) return
      this.renderHistoryAnnotationTaskIds.push(obj.VisitTaskId)
      // let arr = []
      obj.Annotations.map(i => {
        const annotation = i.MeasureData
        annotation.annotationId = i.Id
        cornerstoneTools.annotation.state.addAnnotation(annotation)
        if (obj.ReadingTaskState === 2) {
          cornerstoneTools.annotation.locking.setAnnotationLocked(annotation.annotationUID)
        }
      })
    },
    // 渲染图片
    async renderImage(imageIds, canvasIndex, sliceIndex) {
      metaData.addProvider((type, imageId) => hardcodedMetaDataProvider(type, imageId, imageIds), 10000)
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(`canvas-${canvasIndex}`)
      await viewport.setStack(imageIds)
      this.setToolsPassive()
      viewport.setImageIdIndex(sliceIndex)
      viewport.render()
      // this.updateViewportInfos()
    },
    setActiveCanvasImages(obj) {
      console.log('setActiveCanvasImages')
      if (!obj || Object.keys(obj).length === 0) return
      const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      if (i === -1) return
      if (obj.studyId === this.viewportInfos[i].studyId && this.imageType.includes(this.viewportInfos[i].fileType) && this.imageType.includes(obj.fileInfo.FileType)) {
        const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
        this.sliceIndex(fileIndex)
      } else {
        if (!this.imageType.includes(obj.fileInfo.FileType)) {
          this.fullScreenIndex = null
        }
        this.updateViewportInfos(this.activeCanvasIndex, obj)
      }
      if (this.activeCanvasIndex === this.cells.length - 1) {
        store.dispatch('noneDicomReview/setLastViewportTaskId', obj.visitTaskInfo.VisitTaskId)
      }
      this.setToolsPassive()
    },
    // 激活视图
    activeCanvas(index) {
      if (this.activeCanvasIndex === index) return
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return
      this.activeCanvasIndex = index
      if (index === this.cells.length - 1) {
        store.dispatch('noneDicomReview/setLastViewportTaskId', this.viewportInfos[i].taskInfo.VisitTaskId)
      }
      this.$emit('toggleTask', this.viewportInfos[i].taskInfo)
      this.setToolsPassive()
    },
    // 更新视图信息
    updateViewportInfos(index, obj) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return

      this.viewportInfos[i].taskInfo = obj.visitTaskInfo

      this.viewportInfos[i].currentFileName = obj.fileInfo.FileName
      this.viewportInfos[i].studyId = obj.studyId
      this.viewportInfos[i].fileType = obj.fileInfo.FileType
      if (this.imageType.includes(obj.fileInfo.FileType)) {
        const arr = obj.fileList.filter(i => this.imageType.includes(i.FileType))
        this.viewportInfos[i].fileList = arr
        const fileIndex = this.viewportInfos[i].fileList.findIndex(i => i.Path === obj.fileInfo.Path)
        this.viewportInfos[i].currentImageIdIndex = fileIndex
        const imageIds = []
        for (let i = 0; i < arr.length; i++) {
          const path = arr[i].Path
          imageIds.push(`web:${this.OSSclientConfig.basePath}${path}`)
        }
        this.viewportInfos[i].imageIds = imageIds
        if (imageIds.length > 0) {
          this.renderImage(imageIds, index, fileIndex)
        }
        this.$nextTick(() => {
          const renderingEngine = getRenderingEngine(renderingEngineId)
          if (renderingEngine) {
            renderingEngine.resize(true, false)
          }
        })
      } else {
        this.viewportInfos[i].currentFilePath = obj.fileInfo.Path
      }
    },
    // 切换图片
    sliceIndex(index) {
      const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      if (i === -1) return
      if (index < 0 || index >= this.viewportInfos[i].imageIds.length) return
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(
        this.viewportInfos[i].viewportId
      )
      this.setToolsPassive()
      viewport.setImageIdIndex(index)
      viewport.render()
    },
    // 更改视图布局
    handleCommand(command) {
      this.fullScreenIndex = null
      this.layout = command
      this.rows = parseInt(command.split('*')[0])
      this.cols = parseInt(command.split('*')[1])
      if (this.rows === 1 && this.cols === 1) {
        this.$nextTick(() => {
          this.activeCanvas(0)
        })
      }
      // 有序阅片 1*1 显示当前图片 1*2  显示基线*当前图片  2*2 显示当前图片
      // const obj = this.viewportInfos.find(i => i.index === this.activeCanvasIndex)
      // if (obj && this.rows === 1 && this.cols === 1) {
      //   this.viewportInfos = this.viewportInfos.map((v, i) => {
      //     if (i === 0) {
      //       v.taskInfo = obj.taskInfo
      //       v.currentImageIdIndex === obj.currentImageIdIndex
      //       v.currentFileName === obj.currentFileName
      //       v.imageIds === obj.imageIds
      //     } else {
      //       v.taskInfo = ''
      //       v.currentImageIdIndex === 0
      //       v.currentFileName === ''
      //       v.imageIds === []
      //     }
      //     return v
      //   })
      //   this.activeCanvasIndex = 0
      // } else if (obj && this.rows === 1 && this.cols === 2 && this.taskInfo.IsReadingTaskViewInOrder === 1) {
      //   this.viewportInfos = this.viewportInfos.map((v, i) => {
      //     if (i === 0) {
      //       v.taskInfo = this.relatedStudyInfo.visitTaskInfo
      //       v.currentImageIdIndex === this.relatedStudyInfo.fileIndex
      //       v.currentFileName === this.relatedStudyInfo.fileInfo.FileName
      //       const imageIds = []
      //       for (let i = 0; i < this.relatedStudyInfo.fileList.length; i++) {
      //         const path = this.relatedStudyInfo.fileList[i].Path
      //         imageIds.push(`web:${this.OSSclientConfig.basePath}${path}`)
      //       }
      //       v.imageIds === imageIds
      //     } else if (i === 1) {
      //       v.taskInfo = obj.taskInfo
      //       v.currentImageIdIndex === obj.currentImageIdIndex
      //       v.currentFileName === obj.currentFileName
      //       v.imageIds === obj.imageIds
      //     } else {
      //       v.taskInfo = ''
      //       v.currentImageIdIndex === 0
      //       v.currentFileName === ''
      //       v.imageIds === []
      //     }
      //     return v
      //   })
      //   this.activeCanvasIndex = 1
      // } else if (obj && this.rows === 1 && this.cols === 2 && this.taskInfo.IsReadingTaskViewInOrder !== 1) {
      //   this.viewportInfos = this.viewportInfos.map((v, i) => {
      //     if (i === 0 || i === 1) {
      //       v.taskInfo = obj.taskInfo
      //       v.currentImageIdIndex === obj.currentImageIdIndex
      //       v.currentFileName === obj.currentFileName
      //       v.imageIds === obj.imageIds
      //     } else {
      //       v.taskInfo = ''
      //       v.currentImageIdIndex === 0
      //       v.currentFileName === ''
      //       v.imageIds === []
      //     }
      //     return v
      //   })
      //   this.activeCanvasIndex = 1
      // } else if (obj && (this.rows === 2 && this.cols === 2)) {
      //   this.viewportInfos = this.viewportInfos.map(v => {
      //     v.taskInfo = obj.taskInfo
      //     v.currentImageIdIndex === obj.currentImageIdIndex
      //     v.currentFileName === obj.currentFileName
      //     v.imageIds === obj.imageIds
      //     return v
      //   })
      //   this.activeCanvasIndex = 3
      // }
      // this.$nextTick(() => {
      //   this.viewportInfos.forEach(v => {
      //     if (v.imageIds.length > 0) {
      //       this.renderImage(v.imageIds, v.index, v.currentImageIdIndex)
      //     }
      //   })
      // })
    },
    getCellStyle(index) {
      return {
        ...this.cellStyle,
        display: index < this.cells.length ? this.cellStyle.display : 'none'
      }
    },
    // 切换全屏
    toggleFullScreen(e, index) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return
      if (!this.viewportInfos[i].currentFileName) return
      if (this.imageType.includes(this.viewportInfos[i].fileType)) {
        this.fullScreenIndex = this.fullScreenIndex === index ? null : index
        this.activeCanvasIndex = index
      }
    },
    // 切换任务
    toggleTask(evt, visitTaskNum, i, index) {
      this.activeCanvas(index)
      const num = visitTaskNum + i
      if (num >= 0 && num <= this.taskInfo.VisitNum) {
        this.$emit('toggleTaskByViewer', num)
      }

      evt.stopImmediatePropagation()
      evt.stopPropagation()
      evt.preventDefault()
    },
    // 激活工具
    setToolActive(toolName) {
      const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      if (i === -1) return
      const toolGroupId = `canvas-${this.viewportInfos[i].index}`
      const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
      if (this.activeTool === toolName) {
        toolGroup.setToolPassive(this.activeTool)
        this.activeTool = ''
      } else {
        if (this.activeTool) {
          toolGroup.setToolPassive(this.activeTool)
        }
        toolGroup.setToolActive(toolName, {
          bindings: [{ mouseButton: MouseBindings.Primary }]
        })
        this.activeTool = toolName
      }
    },
    // 激活标注工具
    setAnnotateToolActive(toolName) {
      // if (this.readingTaskState === 2) return
      if (this.readingTaskState === 2 && toolName === 'Lengthscale') return
      const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      if (i === -1) return
      if (this.viewportInfos[i].taskInfo.VisitTaskId === this.taskInfo.VisitTaskId) {
        const toolGroupId = `canvas-${this.viewportInfos[i].index}`
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        if (this.activeTool === toolName) {
          toolGroup.setToolPassive(this.activeTool)
          this.activeTool = ''
        } else {
          if (this.activeTool) {
            toolGroup.setToolPassive(this.activeTool)
          }
          if (toolName === 'Lengthscale') {
            const renderingEngine = getRenderingEngine(renderingEngineId)
            const viewport = renderingEngine.getViewport(`canvas-${this.activeCanvasIndex}`)
            const imageId = viewport.csImage.imageId
            const annotations = cornerstoneTools.annotation.state.getAllAnnotations()
            const idx = annotations.findIndex(i => i.metadata.referencedImageId === imageId && i.metadata.toolName === 'Lengthscale')
            if (idx > -1) {
              this.activeTool = ''
              // 当前图像已存在比例尺！
              this.$message.warning(this.$t('trials:noneDicom:message:msg4'))
              return
            }
          }
          toolGroup.setToolActive(toolName, {
            bindings: [{ mouseButton: MouseBindings.Primary }]
          })
          this.activeTool = toolName
        }
      }
    },
    setToolsPassive() {
      if (!this.activeTool) return
      const toolGroupIds = ['canvas-0', 'canvas-1', 'canvas-2', 'canvas-3']
      toolGroupIds.forEach(toolGroupId => {
        const toolGroup = ToolGroupManager.getToolGroup(toolGroupId)
        toolGroup.setToolPassive(this.activeTool)
      })
      this.activeTool = ''
      // const enabledElement = getEnabledElementByIds(
      //   `canvas-${this.activeCanvasIndex}`,
      //   renderingEngineId
      // )
      // cursors.setCursorForElement(enabledElement.viewport.element, 'default')
    },
    addAnnotationListeners() {
      const debouncedCallback = this.debounce((evt) => {
        this.annotationModifiedListener(evt)
      }, 0)
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_MODIFIED,
        (evt) => {
          debouncedCallback(evt)
        }
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_COMPLETED,
        this.annotationCompletedListener
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_REMOVED,
        this.annotationRemovedListener
      )
      eventTarget.addEventListener(
        toolsEvents.ANNOTATION_SELECTION_CHANGE,
        this.annotationSelectionChangeListener
      )
    },
    async annotationRemovedListener(e) {
      const { annotation } = e.detail
      try {
        // if ( this.resetAnnotation && this.isFusion ) return false
        if (!annotation) return false
        // if (annotation.metadata.toolName === 'Lengthscale') {
        //   await this.$confirm(
        //     this.$t('trials:trials-list:table:LengthscaleIsDeleted')
        //   )
        //   const errorMsg = { message: 'Lengthscale Not delete' }
        //   throw errorMsg
        // }
        if (this.readingTaskState === 2 && !annotation.data.label && annotation.metadata.toolName !== 'Lengthscale') 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 && annotation.metadata.toolName !== 'Lengthscale') {
          // 临时标记
          return
        }
        // this.$emit('getMarkedFileIds', { type: "remove", visitTaskId: this.taskInfo.VisitTaskId, fileId: annotation.noneDicomFileId})
        if (annotation.visitTaskId === this.taskInfo.VisitTaskId) {
          this.$emit('getEcrf', { type: "verifyAnnotationIsBound", VisitTaskId: annotation.visitTaskId, annotation })
          this.$nextTick(async () => {
            try {
              const isBound = this.ecrf.isBound
              if (isBound && this.activeTool === 'Eraser') {
                // '该标记已与问题进行绑定，不允许删除！'
                this.$alert(this.$t('dicom3D:ReadPage:alert:MarkToQuestionNoDel'))
                const errorMsg = { message: 'annotation Not allowed to operate' }
                throw errorMsg
              } else if (this.activeTool === 'Eraser') {
                if (annotation.metadata.toolName === 'Lengthscale') {
                  await this.$confirm(
                    this.$t('trials:trials-list:table:isDeleted') +
                    this.$t('trials:nondicom-show:scale') +
                    '?'
                  )
                } else {
                  await this.$confirm(
                    this.$t('trials:trials-list:table:isDeleted') +
                    annotation.data.label +
                    '?'
                  )
                }

                if (annotation.id) {
                  let res = await deleteTrialFileType(annotation.id)
                  this.$emit('getMarkedFileIds', { type: "remove", visitTaskId: this.taskInfo.VisitTaskId, fileId: annotation.noneDicomFileId })
                  if (!res.IsSuccess) throw ''
                }
                if (annotation.metadata.toolName === 'Lengthscale') {
                  let psIndex = this.psArr.findIndex(item => item.Path === annotation.path)
                  if (psIndex > -1) {
                    this.psArr.splice(psIndex, 1)
                  }
                  this.$emit('getEcrf', { type: "changePlottingScaleChangeAnswer", VisitTaskId: this.taskInfo.VisitTaskId, noneDicomFileId: annotation.noneDicomFileId, path: annotation.path || '', picturePath: null, psArr: this.psArr, isRemovePlottingScale: false })
                  this.setToolsPassive()
                }
                const renderingEngine = getRenderingEngine(renderingEngineId)
                for (let i = 0; i < this.cells.length; i++) {
                  const viewportId = `canvas-${i}`
                  const viewport = renderingEngine.getViewport(viewportId)
                  viewport.render()
                }
              }
              // else {
              //   console.log(1234567)
              //   const errorMsg = { message: 'annotation Not allowed to operate' }
              //   throw errorMsg
              // }
            } catch (err) {
              cornerstoneTools.annotation.state.addAnnotation(annotation)
              const renderingEngine = getRenderingEngine(renderingEngineId)
              for (let i = 0; i < this.cells.length; i++) {
                const viewportId = `canvas-${i}`
                const viewport = renderingEngine.getViewport(viewportId)
                viewport.render()
              }
              console.log(e)
            }
          })

        }

      } catch (e) {
        cornerstoneTools.annotation.state.addAnnotation(annotation)
        const renderingEngine = getRenderingEngine(renderingEngineId)
        for (let i = 0; i < this.cells.length; i++) {
          const viewportId = `canvas-${i}`
          const viewport = renderingEngine.getViewport(viewportId)
          viewport.render()
        }
        console.log(e)
      }
    },
    async annotationModifiedListener(e) {
      console.log('Modified')
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation.highlighted) return
      if (!annotation) return
      const savedAnnotationId = annotation.id || annotation.annotationId
      if (!savedAnnotationId && annotation.metadata.toolName !== 'Lengthscale') return
      let i = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
      if (i === -1 && annotation.metadata.toolName !== 'Lengthscale') {
        this.setToolsPassive()
        return
      }
      i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      const imageId = annotation.metadata.referencedImageId
      const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const fileList = this.viewportInfos[i].fileList
      const fileIndex = fileList.findIndex(f => f.Path === path)
      if (fileIndex === -1) return
      annotation.path = path
      let ps = null
      let psIndex = this.psArr.findIndex(i => i.Path === path)
      if (psIndex > -1 && this.psArr[psIndex].PS) {
        ps = parseFloat(this.psArr[psIndex].PS).toFixed(3)
      }
      annotation.ps = ps
      if (!annotation.data.label && annotation.metadata.toolName !== 'Lengthscale') return
      if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
      if (annotation.metadata.toolName === 'Lengthscale') {
        const value = annotation.data.l
        if (isNaN(parseFloat(value))) return false
        let ps = 1
        if (value) {
          const cachedStats = Object.keys(annotation.data.cachedStats)
          ps = value / annotation.data.cachedStats[cachedStats[0]].length
          annotation.data.ps = ps
          this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: ps })
        }
        this.setToolsPassive()
        if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
        this.curOperation.type = 'Modified'
        return this.curOperation.annotation = annotation
      }
      this.$emit("getEcrf", { type: "getOperateStateEnum", VisitTaskId: this.taskInfo.VisitTaskId })
      this.$emit('getEcrf', { type: "verifyAnnotationIsBound", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
      this.$nextTick(() => {
        const operateStateEnum = this.ecrf.operateStateEnum
        const isBound = this.ecrf.isBound
        if (isBound || this.isNumber(operateStateEnum)) {
          this.$emit('getEcrf', { type: "updateAnnotationToQuestion", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
        } else {
          this.curOperation.type = 'Modified'
          this.curOperation.annotation = annotation
        }
        this.setToolsPassive()
      })
    },
    async annotationCompletedListener(e) {
      console.log('Completed')
      if (this.readingTaskState === 2) return
      const { annotation } = e.detail
      if (!annotation) return
      const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
      let INDEX = this.tools.findIndex(i => i.toolName === annotation.metadata.toolName)
      if ((INDEX === -1 && annotation.metadata.toolName !== 'Lengthscale') || i === -1) {
        this.setToolsPassive()
        return
      }

      if (annotation.metadata.toolName === 'PlanarFreehandROI' && !annotation.data.contour.closed) return
      if (this.viewportInfos[i].taskInfo.VisitTaskId !== this.taskInfo.VisitTaskId) return
      const imageId = annotation.metadata.referencedImageId
      const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const fileList = this.viewportInfos[i].fileList
      const fileIndex = fileList.findIndex(f => f.Path === path)
      if (fileIndex === -1) return
      annotation.path = path
      let ps = null
      let psIndex = this.psArr.findIndex(i => i.Path === path)
      if (psIndex > -1 && this.psArr[psIndex].PS) {
        ps = parseFloat(this.psArr[psIndex].PS).toFixed(3)
      }
      annotation.ps = ps
      annotation.markTool = annotation.metadata.toolName
      annotation.visitTaskId = this.viewportInfos[i].taskInfo.VisitTaskId
      annotation.studyId = this.viewportInfos[i].studyId
      annotation.noneDicomFileId = this.viewportInfos[i].fileList[this.viewportInfos[i].currentImageIdIndex].Id
      if (annotation.metadata.toolName === 'Lengthscale') {
        this.form.annotationObj = {
          id: '',
          visitTaskId: this.viewportInfos[i].taskInfo.VisitTaskId,
          studyId: this.viewportInfos[i].studyId,
          noneDicomFileId: fileList[fileIndex].Id,
          path: fileList[fileIndex].Path,
          annotation,
          fileList,
          fileIndex
        }
        this.form.length = null
        this.dialogVisible = true
        this.setToolsPassive()
        return
      }
      // this.markedSeriesIds.push(series.Id)
      this.$emit('getEcrf', { type: "getOperateStateEnum", VisitTaskId: this.taskInfo.VisitTaskId })

      this.$nextTick(async () => {
        const operateStateEnum = this.ecrf.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.$emit('getEcrf', { type: "bindAnnotationToQuestion", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
          } else {
            if (this.saveCustomAnnotationTimer) {
              clearTimeout(this.saveCustomAnnotationTimer)
              this.saveCustomAnnotationTimer = null
            }
            this.saveCustomAnnotation(annotation)
          }
        } else {
          // if (this.isNumber(operateStateEnum)) {
          //   this.removeAnnotation(annotation)
          // }  
        }
      })
    },
    annotationSelectionChangeListener(e) {
      console.log('selection')
      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 {
          let annotation = annotations[i]
          const imageId = annotation.metadata.referencedImageId
          const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
          let psIndex = this.psArr.findIndex(i => i.Path === path)
          let ps = null
          if (psIndex > -1 && this.psArr[psIndex].PS) {
            ps = parseFloat(this.psArr[psIndex].PS).toFixed(3)
          }
          annotation.ps = ps
          this.$emit('getEcrf', { type: "bindAnnotationToQuestion", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
        }
      }
    },
    async saveCustomAnnotation(annotation, ps = null) {
      try {
        const measureData = Object.assign({}, annotation)
        const params = {}
        const savedAnnotationId = annotation.id || annotation.annotationId
        const i = this.viewportInfos.findIndex(i => i.index === this.activeCanvasIndex)
        this.loading = true
        await this.getScreenshots({
          visitTaskId: this.taskInfo.VisitTaskId,
          annotation
        }, async (base64Str) => {
          this.loading = false
          const pictureObj = await this.uploadScreenshots(`${Date.now()}`, base64Str)
          let picturePath = pictureObj.isSuccess ? this.$getObjectName(pictureObj.result.url) : ''
          if (savedAnnotationId) params.Id = savedAnnotationId
          if (!isNaN(parseFloat(ps))) params.Proportion = ps
          params.PicturePath = picturePath
          params.Path = annotation.path || ''
          params.MarkTool = measureData.markTool
          params.OrderMarkName = measureData.data.label
          params.VisitTaskId = this.taskInfo.VisitTaskId
          params.StudyId = annotation.studyId
          params.NoneDicomFileId = annotation.noneDicomFileId
          params.MeasureData = JSON.stringify(measureData)
          params.MarkId = annotation.annotationUID
          const res = await addNoneDicomMark(params)
          annotation.markId = params.MarkId
          annotation.id = res.Result
          annotation.annotationId = res.Result
          if (!isNaN(parseFloat(ps))) this.$emit('getEcrf', { type: "changePlottingScaleChangeAnswer", VisitTaskId: this.taskInfo.VisitTaskId, noneDicomFileId: annotation.noneDicomFileId, path: annotation.path || '', picturePath, psArr: this.psArr, isRemovePlottingScale: ps < 0 ? true : false })

          this.$emit('getMarkedFileIds', { type: "add", visitTaskId: this.taskInfo.VisitTaskId, fileId: annotation.noneDicomFileId })
        })

      } catch (e) {
        this.loading = false
        console.log(e)
      }
    },
    async getScreenshots(measureData, callback) {
      if (measureData) {
        // await this.imageLocation(measureData)
        this.viewCustomAnnotation(measureData)
        const divForDownloadViewport = document.querySelector(
          `div[data-viewport-uid="canvas-${this.activeCanvasIndex}"]`
        )
        const canvas = await html2canvas(divForDownloadViewport)
        const base64Str = canvas.toDataURL('image/png', 1)
        callback(base64Str)
      } else {
        callback()
      }
    },
    viewCustomAnnotation(obj) {
      const i = this.viewportInfos.findIndex(i => i.taskInfo.VisitTaskId === obj.visitTaskId)
      const imageId = obj.annotation.metadata.referencedImageId
      const path = imageId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const fileList = this.viewportInfos[i].fileList
      const fileIndex = fileList.findIndex(f => f.Path === path)
      let o = { fileInfo: fileList[fileIndex], fileList, visitTaskInfo: this.viewportInfos[i].taskInfo, studyId: this.viewportInfos[i].studyId }
      this.setActiveCanvasImages(o)
    },
    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}/${this.taskInfo.VisitTaskId}/${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 })
    },
    isNumber(value) {
      return typeof value === 'number' && value !== null && !isNaN(value)
    },
    async saveForm() {
      const validate = await this.$refs.lengthForm.validate()
      if (!validate) return
      const value = this.form.length
      const annotation = this.form.annotationObj.annotation
      const fileList = this.form.annotationObj.fileList
      const fileIndex = this.form.annotationObj.fileIndex
      let ps = 1
      if (value) {
        annotation.data.l = parseFloat(value)
        const cachedStats = Object.keys(annotation.data.cachedStats)
        ps = parseFloat(value) / annotation.data.cachedStats[cachedStats[0]].length
        annotation.data.ps = ps
        this.$emit('setPS', { NoneDicomFileId: fileList[fileIndex].Id, Path: fileList[fileIndex].Path, PS: ps })
      } else {
        cornerstoneTools.annotation.state.removeAnnotation(annotation.annotationUID)
        return
      }
      if (this.customizeStandardsNoneDicom.find(item => item.toolName === annotation.metadata?.toolName)) return false
      this.dialogVisible = false
      this.$emit('getEcrf', { type: "verifyFileIsBound", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
      this.$nextTick(() => {
        if (this.saveCustomAnnotationTimer) {
          clearTimeout(this.saveCustomAnnotationTimer)
          this.saveCustomAnnotationTimer = null
        }
        return this.saveCustomAnnotationTimer = setTimeout(async () => {
          if (!this.ecrf.IsHaveBindingQuestion || !this.ecrf.isFileBound) {
            this.saveCustomAnnotation(annotation)
          } else {
            await this.$confirm(
              this.$t('trials:trials-list:table:allQuestionChange'), '', {
              showClose: false,
              showCancelButton: false,
              closeOnClickModal: false,
              closeOnPressEscape: false
            }
            ).then(() => {
              this.saveCustomAnnotation(annotation, 1)
            })
              .catch(action => {
                this.saveCustomAnnotation(annotation, -1)
              });
          }
        }, 500)
        this.saveCustomAnnotationTimer = setTimeout(() => { this.saveCustomAnnotation(annotation) }, 500)
      })

    },
    getLengthscaleToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { length, unit } = cachedVolumeStats
      if (length === undefined || length === null || isNaN(length)) {
        return
      }
      if (data.l === undefined || data.l === null || isNaN(data.l)) {
        return
      }
      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      textLines.push(`P: ${parseFloat(length).toFixed(this.digitPlaces)} ${unit}`)
      if (data.l) {
        textLines.push(`L: ${parseFloat(data.l).toFixed(this.digitPlaces)} mm`)
        textLines.push(`PS: ${parseFloat(data.l / length).toFixed(3)} mm/px`)
      }
      return textLines
    },
    // 长短径工具注释
    getBidirectionalToolTextLines(data, targetId) {
      const { cachedStats, label } = data
      const { length, width, unit } = cachedStats[targetId]
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      const textLines = []
      if (label) {
        textLines.push(data.status ? `${label}(${data.status})` : label)
      }
      if (length === undefined) {
        return textLines
      }
      if (ps) {
        textLines.push(
          `L: ${this.reRound(csUtils.roundNumber(length * ps), this.digitPlaces)} mm`,
          `S: ${this.reRound(csUtils.roundNumber(width * ps), this.digitPlaces)} mm`
        )
      } else {
        textLines.push(
          `L: ${this.reRound(csUtils.roundNumber(length), this.digitPlaces)} ${unit || unit}`,
          `S: ${this.reRound(csUtils.roundNumber(width), this.digitPlaces)} ${unit}`
        )
      }


      return textLines
    },
    // 直线工具注释
    getLengthToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      let { length, unit } = cachedVolumeStats
      if (length === undefined || length === null || isNaN(length)) {
        return
      }
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      if (ps) {
        textLines.push(`${this.reRound(csUtils.roundNumber(length * ps), this.digitPlaces)} mm`)
      } else {
        textLines.push(`${this.reRound(csUtils.roundNumber(length), this.digitPlaces)} ${unit}`)
      }
      return textLines
    },
    getPlanarFreehandROIToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const {
        area,
        mean,
        stdDev,
        // length,
        perimeter,
        max,
        isEmptyArea,
        unit,
        areaUnit,
        modalityUnit
      } = cachedVolumeStats || {}

      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      if (area) {
        const areaLine = isEmptyArea
          ? `Area: Oblique not supported`
          : `Area: ${ps ? this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces) : this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${ps ? 'mm' + '\xb2' : areaUnit}`
        textLines.push(areaLine)
      }
      if (mean) {
        textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
      }

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

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

      if (perimeter) {
        if (ps) {
          textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
        } else {
          textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} ${unit}`)
        }
      }

      // if (length) {
      //   // No need to show length prefix as there is just the single value
      //   textLines.push(`${csUtils.roundNumber(length)} ${unit}`);
      // }

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

      if (mean === undefined) {
        return
      }

      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      if (ps) {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
      } else {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
      }
      textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
      if (Array.isArray(points) && points.length === 4) {
        let perimeter = 2 * Math.abs(points[0][0] - points[1][0]) + 2 * Math.abs(points[1][1] - points[2][1])
        if (perimeter) {
          if (ps) {
            textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
          } else {
            textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} px`)
          }
        }
      }
      return textLines
    },
    // 椭圆工具注释信息
    getEllipticalROIToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { area, mean, max, stdDev, areaUnit, modalityUnit } = cachedVolumeStats

      if (mean === undefined) {
        return
      }

      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      if (ps) {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
      } else {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
      }
      textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
      return textLines
    },
    // 圆形工具注释信息
    getCircleROIToolTextLines(data, targetId) {
      const cachedVolumeStats = data.cachedStats[targetId]
      const { area, mean, max, stdDev, perimeter, areaUnit, modalityUnit } = cachedVolumeStats

      if (mean === undefined) {
        return
      }

      const textLines = []
      if (data.label) {
        textLines.push(data.label)
      }
      let ps = null
      const path = targetId.split(`web:${this.OSSclientConfig.basePath}`)[1]
      const i = this.psArr.findIndex(i => i.Path === path)
      if (i > -1 && this.psArr[i].PS) {
        ps = parseFloat(this.psArr[i].PS).toFixed(3)
      }
      if (ps) {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area * ps * ps), this.digitPlaces)} ${'mm' + '\xb2'}`)
      } else {
        textLines.push(`Area: ${this.reRound(csUtils.roundNumber(area), this.digitPlaces)} ${areaUnit}`)
      }
      textLines.push(`Mean: ${this.reRound(csUtils.roundNumber(mean), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Max: ${this.reRound(csUtils.roundNumber(max), this.digitPlaces)} ${modalityUnit}`)
      textLines.push(`Std Dev: ${this.reRound(csUtils.roundNumber(stdDev), this.digitPlaces)} ${modalityUnit}`)
      if (perimeter) {
        if (ps) {
          textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter * ps), this.digitPlaces)} mm`)
        } else {
          textLines.push(`Perimeter: ${this.reRound(csUtils.roundNumber(perimeter), this.digitPlaces)} px`)
        }
      }
      return textLines
    },
    // 角度工具注释信息
    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(`${this.reRound(csUtils.roundNumber(angle), 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)
    },
    debounce(callback, delay) {
      let timerId
      return function () {
        clearTimeout(timerId)
        timerId = setTimeout(() => {
          callback.apply(this, arguments)
        }, delay)
      }
    },
    // 重置视图
    resetViewport() {
      this.setToolsPassive()
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `canvas-${this.activeCanvasIndex}`
      const viewport = (renderingEngine.getViewport(viewportId))
      viewport.resetCamera({ resetPan: true, resetZoom: true, resetToCenter: true })
      renderingEngine.render()
    },
    setZoomScale(isZoomIn) {
      this.setToolsPassive()
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewportId = `canvas-${this.activeCanvasIndex}`
      const viewport = renderingEngine?.getViewport(viewportId)
      if (!viewport) return
      const camera = viewport.getCamera()
      const factor = 1.1
      const current = Number(camera.parallelScale)
      if (!Number.isFinite(current) || current <= 0) return
      const next = isZoomIn ? current / factor : current * factor
      const parallelScale = Math.max(0.0001, Math.min(1000000, next))
      viewport.setCamera({ parallelScale })
      viewport.render()
    },
    async saveImage() {
      const viewportIndex = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
      if (viewportIndex === -1) return
      const currentViewport = this.viewportInfos[viewportIndex]

      let divForDownloadViewport = null
      let tempImg = null

      if (currentViewport.fileType && currentViewport.fileType.includes('mp4')) {
        divForDownloadViewport = this.$refs[`grid-cell-${this.activeCanvasIndex}`][0]
        const videoEl = this.$refs[`videovideo-${this.activeCanvasIndex}`][0]

        if (videoEl) {
          // 将视频帧画到 canvas 上生成图片
          const tempCanvas = document.createElement('canvas')
          // 设置 canvas 尺寸为容器实际尺寸
          const containerWidth = videoEl.clientWidth
          const containerHeight = videoEl.clientHeight
          tempCanvas.width = containerWidth
          tempCanvas.height = containerHeight

          const ctx = tempCanvas.getContext('2d')
          // 填充黑色背景
          ctx.fillStyle = '#000'
          ctx.fillRect(0, 0, containerWidth, containerHeight)

          // 计算视频保持比例的缩放尺寸和位置 (等同于 object-fit: contain)
          const videoWidth = videoEl.videoWidth || containerWidth
          const videoHeight = videoEl.videoHeight || containerHeight

          const scale = Math.min(containerWidth / videoWidth, containerHeight / videoHeight)
          const drawWidth = videoWidth * scale
          const drawHeight = videoHeight * scale
          const offsetX = (containerWidth - drawWidth) / 2
          const offsetY = (containerHeight - drawHeight) / 2

          // 将视频帧居中绘制
          ctx.drawImage(videoEl, offsetX, offsetY, drawWidth, drawHeight)

          const frameBase64 = tempCanvas.toDataURL('image/png')

          // 创建一个 img 标签遮盖在 video 上
          tempImg = document.createElement('img')
          tempImg.src = frameBase64
          tempImg.style.position = 'absolute'
          tempImg.style.top = '0'
          tempImg.style.left = '0'
          tempImg.style.width = '100%'
          tempImg.style.height = '100%'
          tempImg.style.zIndex = '99'

          const videoContainer = this.$refs[`video-content-main-${this.activeCanvasIndex}`][0]
          videoContainer.style.position = 'relative'
          videoContainer.appendChild(tempImg)
        }
      } else {
        divForDownloadViewport = document.querySelector(
          `div[data-viewport-uid="canvas-${this.activeCanvasIndex}"]`
        )
      }

      if (!divForDownloadViewport) return

      // 等待 DOM 更新
      await this.$nextTick()

      const canvas = await html2canvas(divForDownloadViewport, {
        useCORS: true,
        backgroundColor: '#000000' // 指定截图背景为黑色
      })

      // 截图后恢复
      if (tempImg) {
        tempImg.remove()
      }

      const base64Str = canvas.toDataURL('image/png', 1)
      const downloadName = `${Date.now()}.png`

      const a = document.createElement('a')
      a.href = base64Str
      a.download = downloadName
      document.body.appendChild(a)
      a.click()
      a.remove()
    },
    resetAnnotations({ annotations, visitTaskId }) {
      // 移除病灶
      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)
        }
      })
      const renderingEngine = getRenderingEngine(renderingEngineId)
      for (let i = 0; i < this.cells.length; i++) {
        const viewportId = `canvas-${i}`
        const viewport = renderingEngine.getViewport(viewportId)
        viewport.render()
      }
    },
    // 输入标记名称自定义弹窗
    async customPrompt(isShowCancelButton = true) {
      try {
        const that = this
        // 请输入标记名称
        let message = this.$t('trials:noneDicom:message:msg1')
        // if (isShowCancelButton) {
        //   message = `<div><p>${this.$t('trials:noneDicom:message:msg1')}</p><p style='font-size:12px' class='customPromptTip'>${this.$t('trials:noneDicom:message:saveTip')}</p></div>`
        // }
        const { value } = await this.$prompt(message, '', {
          showClose: false,
          cancelButtonText: isShowCancelButton ? this.$t('trials:reading:button:temporarySave') : this.$t('common:button:cancel'),
          confirmButtonText: isShowCancelButton ? this.$t('trials:reading:button:enduringSave') : this.$t('trials:reading:button:relevancy'),
          // showCancelButton: isShowCancelButton,
          // dangerouslyUseHTMLString: isShowCancelButton,
          inputValidator: (res) => {
            if (!res) {
              return isShowCancelButton ? this.$t('trials:noneDicom:message:saveTip') : this.$t('trials:noneDicom:message:saveTipByRelevancy')
            }
          },
          inputErrorMessage: this.$t('trials:noneDicom:message:saveTip'),
          showCancelButton: true,
          closeOnClickModal: false,
          closeOnPressEscape: false,
          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 (err) {
        console.log(err)
        return null
      }
    },
    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
    },
    // 滚动条
    clickSlider(e, index) {
      const height = e.offsetY * 100 / this.$refs[`sliderBox-${index}`][0].clientHeight
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return
      this.viewportInfos[i].height = height
      let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
      sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(
        this.viewportInfos[i].viewportId
      )
      this.setToolsPassive()
      viewport.setImageIdIndex(sliceIdx)
      viewport.render()
      // this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, imageIndex: sliceIdx })
    },
    sliderMouseup(e, index) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
      this.viewportInfos[i].isMove = false
    },
    sliderMousemove(e, index) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
      if (!this.viewportInfos[i].isMove) return
      const delta = this.viewportInfos[i].oldB - (this.viewportInfos[i].oldM - e.clientY)
      const boxHeight = this.$refs[`sliderBox-${index}`][0].clientHeight
      if (delta < 0) return
      if (delta > boxHeight) return
      const height = delta * 100 / boxHeight
      let sliceIdx = Math.trunc(this.viewportInfos[i].imageIds.length * height / 100)
      sliceIdx = sliceIdx >= this.viewportInfos[i].imageIds.length ? this.viewportInfos[i].imageIds.length - 1 : sliceIdx < 0 ? 0 : sliceIdx
      this.viewportInfos[i].height = height
      // if (this.viewportInfos[i].currentImageIdIndex !== i) {
      const renderingEngine = getRenderingEngine(renderingEngineId)
      const viewport = renderingEngine.getViewport(
        this.viewportInfos[i].viewportId
      )
      this.setToolsPassive()
      viewport.setImageIdIndex(sliceIdx)
      viewport.render()
      // }
      // this.$emit('toggleImage', { taskId: this.viewportInfos[i].taskInfo.VisitTaskId, studyId: this.viewportInfos[i].studyId, imageIndex: sliceIdx })
    },
    sliderMouseleave(e, index) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1 && this.imageType.includes(this.viewportInfos[i].fileType)) return
      if (!this.viewportInfos[i].isMove) return
      this.viewportInfos[i].isMove = false
    },
    sliderMousedown(e, index) {
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return
      const boxHeight = this.$refs[`sliderBox-${index}`][0].clientHeight
      this.viewportInfos[i].oldB = parseInt(e.srcElement.style.top) * boxHeight / 100
      this.viewportInfos[i].oldM = e.clientY
      this.viewportInfos[i].isMove = true
      e.stopImmediatePropagation()
      e.stopPropagation()
      e.preventDefault()
    },
    contentMouseup(e, index) {
      console.log('contentMouseup')
      const i = this.viewportInfos.findIndex(i => i.index === index)
      if (i === -1) return
      if (this.curOperation.type === 'Modified') {
        let annotation = this.curOperation.annotation
        const savedAnnotationId = annotation.id || annotation.annotationId
        if (!savedAnnotationId && annotation.metadata.toolName !== 'Lengthscale') {
          this.curOperation = {
            type: '',
            annotation: null
          }
          return
        }
        if (annotation.metadata.toolName === 'Lengthscale') {
          this.$emit('getEcrf', { type: "verifyFileIsBound", VisitTaskId: this.taskInfo.VisitTaskId, annotation })
          this.$nextTick(() => {
            if (!this.ecrf.IsHaveBindingQuestion || !this.ecrf.isFileBound) {
              this.saveCustomAnnotation(annotation)
            } else {
              this.$confirm(
                this.$t('trials:trials-list:table:allQuestionChange'), '', {
                showClose: false,
                showCancelButton: false,
                closeOnClickModal: false,
                closeOnPressEscape: false
              }
              ).then(() => {
                this.saveCustomAnnotation(annotation, 1)
              })
                .catch(action => {
                  this.saveCustomAnnotation(annotation, -1)
                });
            }
          })
        } else {
          if ((annotation.metadata.toolName === 'ArrowAnnotate' && annotation.data.label === 'Annotation') || annotation.data.label === '') {
            return
          }
          this.saveCustomAnnotation(annotation)
        }
      }
      this.curOperation = {
        type: '',
        annotation: null
      }
      // e.stopImmediatePropagation()
      // e.stopPropagation()
      // e.preventDefault()
    },
    handleIframeMessage(event) {
      if (event.data.type === 'pdf-clicked') {
        const baseUrl = event.data.data.baseUrl
        const urlParams = new URL(baseUrl)
        const index = parseInt(urlParams.search.split('=')[1])
        this.activeCanvas(index)
      }
    },
    preventDefault(e) {
      e.stopImmediatePropagation()
      e.stopPropagation()
      e.preventDefault()
    },
    // 查看临床数据
    viewCD(id) {
      this.$emit('previewCD', id)
    },
    previewConfig() {
      this.activeName = '1'
      this.personalConfigDialog.visible = true
    },
    // 获取热键配置信息
    async getHotKeys() {
      try {
        const res = await getDoctorShortcutKey({ imageToolType: 2 })
        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']
      if (!container) return
      container.tabIndex = 0
      container.focus()
      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 canvasIndex = this.activeCanvasIndex === 0 ? this.activeCanvasIndex : this.activeCanvasIndex - 1
          this.activeCanvas(canvasIndex)
        } else if (shortcutKeyEnum === 2) {
          // 后一图像视口
          const canvasIndex = this.activeCanvasIndex === this.cells.length - 1 ? this.activeCanvasIndex : this.activeCanvasIndex + 1
          this.activeCanvas(canvasIndex)
        } else if (shortcutKeyEnum === 5) {
          // 上一张图像
          const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
          if (i > -1 && this.imageType.includes(this.viewportInfos[i].fileType)) {
            this.sliceIndex(this.viewportInfos[i].currentImageIdIndex - 1)
          }
        } else if (shortcutKeyEnum === 6) {
          // 下一张图像
          const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
          if (i > -1 && this.imageType.includes(this.viewportInfos[i].fileType)) {
            this.sliceIndex(this.viewportInfos[i].currentImageIdIndex + 1)
          }
        } else if (shortcutKeyEnum === 11) {
          // 放大
          const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
          if (i > -1 && this.imageType.includes(this.viewportInfos[i].fileType)) {
            this.setZoomScale(true)
          }
        } else if (shortcutKeyEnum === 12) {
          // 缩小
          const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
          if (i > -1 && this.imageType.includes(this.viewportInfos[i].fileType)) {
            this.setZoomScale(false)
          }
        } else if (shortcutKeyEnum === 15) {
          // 截图
          const i = this.viewportInfos.findIndex(v => v.index === this.activeCanvasIndex)
          if (i > -1 && this.imageType.includes(this.viewportInfos[i].fileType)) {
            this.saveImage()
          }
        } else if (shortcutKeyEnum === 18) {
          // 重置
          this.resetViewport()
        } else if (shortcutKeyEnum === 19) {
          // 显示或隐藏标记
          this.isShowAnnotations = !this.isShowAnnotations
          const { visibility } = cornerstoneTools.annotation
          if (this.isShowAnnotations) {
            visibility.showAllAnnotations()
          } else {
            const annotationUIDs = cornerstoneTools.annotation.state.getAllAnnotations().map((a) => a.annotationUID)
            annotationUIDs.forEach((annotationUID) => {
              visibility.setAnnotationVisibility(annotationUID, false)
            })
          }
          const renderingEngine = getRenderingEngine(renderingEngineId)
          let viewportIds = [`canvas-0`, `canvas-1`, `canvas-2`, `canvas-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 })
      })
    },
  }
}
</script>
<style lang="scss" scoped>
::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;
  }
}

.content {
  cursor: default !important;
}

.dropdown {
  position: relative;
  display: inline-block;

  .text {
    text-align: center;
  }
}

.dropdown-content {
  display: none;
  position: absolute;
  background-color: #383838;
  color: #fff;
  box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
  z-index: 9999;
  font-size: 12px;

  ul {
    list-style: none;
    margin: 0;
    padding: 0;
    text-align: center;

    li {
      a {
        display: block;
        padding: 5px;
      }
    }
  }

  ul li a:hover {
    background-color: #727272;
  }

  .customize-standards-list {
    width: max-content;
    white-space: nowrap;

    li a {
      display: flex;
      align-items: center;
      padding: 8px !important;
      box-sizing: border-box;
    }
  }
}

.none-dicom-viewer {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  user-select: none;

  .tools-wrapper {
    height: 50px;
    display: flex;
    align-items: center;
    border-bottom: 1px solid #727272;
    color: #ddd;
    padding: 0 5px;

    .tools-left {
      flex: 1;
      display: flex;
      flex-direction: row;
      justify-content: flex-start;
      align-items: center;
    }

    .tool-item {
      padding: 5px;
      margin: 0 5px;
      border: 1px solid #333;
      font-size: 20px;
      cursor: pointer;
    }

    .tool-item-active {
      background-color: #607d8b;
    }

    .tool-disabled {
      cursor: not-allowed;
    }
  }

  .viewports-wrapper {
    flex: 1;

    .grid-container {
      display: grid;
      height: 100%;
      width: 100%;
      position: relative;
    }

    .grid-cell {
      border: 1px dashed #ccc;
      display: flex;
      align-items: center;
      justify-content: center;
      overflow: hidden;
      min-width: 0;
      min-height: 0;
      z-index: 1;
    }

    .cell_active {
      border-color: #fafa00 !important;
    }

    .cell-full-screen {
      grid-column: 1 / -1;
      grid-row: 1 / -1;
    }

    .flex_col {
      display: flex;
      flex-direction: column;
    }

    .content {
      width: 100%;
      height: 100%;
      position: relative;

      .left-top-text {
        position: absolute;
        left: 5px;
        top: 5px;
        color: #ddd;
        z-index: 1;
        font-size: 12px;

        .cd-info {
          color: #ddd;
          font-size: 18px;
        }

        .subject-info {
          color: #f44336;
          padding: 5px 0px;
          margin: 0;
        }
      }

      .top-center-tool {
        position: absolute;
        left: 50%;
        top: 5px;
        transform: translateX(-50%);
        z-index: 1;

        .toggle-visit-container {
          display: flex;
        }

        .arrw_icon {
          width: 20px;
          height: 20px;
          background-color: #3f3f3f;
          text-align: center;
          line-height: 20px;
          border-radius: 10%;
        }

        .arrow_text {
          height: 20px;
          line-height: 20px;
          background-color: #00000057;
          color: #fff;
          padding: 0 10px;
          font-size: 14px;
        }
      }

      .right-slider-box {
        position: absolute;
        right: 1px;
        height: calc(100% - 140px);
        transform: translateY(-50%);
        top: calc(50% - 30px);
        width: 10px;
        background: #333;
        z-index: 1;
        cursor: pointer;
      }

      .right-slider-box:after {
        content: '';
        position: absolute;
        bottom: -20px;
        left: 0;
        height: 20px;
        width: 100%;
        background: #333;
      }

      .slider {
        height: 20px;
        width: 100%;
        position: absolute;
        top: 0;
        z-index: 10;
        background: #9e9e9e;
        cursor: move
      }

      .content-main {
        position: relative;
        overflow: hidden;
        background: #1e1e1e;
      }

      video {
        display: block;
        width: 100%;
        height: 100%;
        object-fit: contain;
        object-position: center center;
        background: transparent;
      }
    }
  }

  ::v-deep .el-dialog {
    background: #1e1e1e;
    border: 1px solid #ddd;
    color: #ddd;

    .el-dialog__title {
      color: #fff;
    }

    .el-input .el-input__inner {
      background-color: transparent;
      color: #ddd;
      border: 1px solid #5e5e5e;
    }

    .el-input.is-disabled .el-input__inner {
      background-color: #646464a1;
    }

    .el-form-item__label {
      color: #dfdfdf
    }
  }
}

.personal_config {
  ::v-deep .el-tabs__content {
    height: 450px;
    overflow-y: auto;
  }

  ::v-deep .hot-keys-label {
    color: #dfdfdf !important;
  }

  ::v-deep .shortcut-key-input span {
    color: #dfdfdf !important;
  }
}
</style>
<style lang="scss">
.key-series-popper {
  padding: 8px !important;
  background-color: #1e1e1e !important;
  border: 1px solid #4a4a4a !important;

  .key-series-list {
    width: 340px;
    max-height: 420px;
    overflow-y: auto;
    margin: 0;
    padding: 0;
    list-style: none;

    &::-webkit-scrollbar {
      width: 8px;
    }

    &::-webkit-scrollbar-thumb {
      background: #4a4a4a;
      border-radius: 4px;
    }

    &::-webkit-scrollbar-track {
      background: transparent;
    }
  }

  .key-series-header {
    padding: 5px 12px;
    margin-bottom: 10px;
    background: linear-gradient(180deg, rgba(64, 64, 64, 0.92) 0%, rgba(43, 43, 43, 0.98) 100%);
    border: 1px solid #474747;
    border-radius: 6px;
    box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 6px 18px rgba(0, 0, 0, 0.2);
  }

  .key-series-header-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .key-series-header-title {
    display: flex;
    align-items: center;
    min-width: 0;
  }

  .key-series-header-dot {
    width: 8px;
    height: 8px;
    margin-right: 8px;
    border-radius: 50%;
    background: linear-gradient(180deg, #ffd76a 0%, #f39c12 100%);
    box-shadow: 0 0 8px rgba(243, 156, 18, 0.45);
  }

  .key-series-task-name {
    color: #fff;
    font-size: 15px;
    font-weight: 600;
    line-height: 22px;
    word-break: break-all;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
  }

  .key-series-empty {
    text-align: center;
    color: #999;
    padding: 10px;
  }

  .key-series-item {
    text-align: left;
    display: flex;
    align-items: center;
    padding: 10px;
    cursor: pointer;
    background: linear-gradient(180deg, rgba(46, 46, 46, 0.96) 0%, rgba(40, 40, 40, 0.98) 100%);
    border-radius: 6px;
    margin-bottom: 8px;
    border: 1px solid #353535;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
    // transition: all 0.2s ease;

    &:last-child {
      margin-bottom: 0;
    }

    &:hover {
      background: linear-gradient(180deg, rgba(54, 54, 54, 0.98) 0%, rgba(46, 46, 46, 1) 100%);
      border-color: #5a5a5a;
      // transform: translateY(-1px);
      box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
    }

    .key-series-img {
      width: 60px;
      height: 60px;
      flex-shrink: 0;
      background-color: #000;
      display: flex;
      justify-content: center;
      align-items: center;
      overflow: hidden;
      margin-right: 12px;
      border-radius: 4px;
      border: 1px solid #3a3a3a;

      img {
        width: 100%;
        height: 100%;
        object-fit: contain;
      }

      .default-icon {
        font-size: 24px;
        color: #666;
      }
    }

    .key-series-info {
      flex: 1;
      overflow: hidden;
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      justify-content: flex-start;
      padding-right: 5px;

      .key-series-meta {
        width: 100%;
        overflow: hidden;
        display: flex;
        flex-direction: row;
        align-items: center;
        margin-bottom: 4px;

        &:last-child {
          margin-bottom: 0;
        }
      }

      .key-series-label {
        font-size: 13px;
        color: #aaa;
        margin-right: 4px;
        white-space: nowrap;
      }

      .key-series-uid {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-size: 13px;
        color: #ddd;
        line-height: 1.2;
      }
    }

    .key-series-star {
      margin-left: 10px;
      display: flex;
      align-items: center;
      justify-content: center;
      width: 28px;
      height: 28px;
      border-radius: 50%;
      background: rgba(243, 156, 18, 0.08);
      border: 1px solid rgba(243, 156, 18, 0.16);

      .svg-icon {
        color: #f39c12;
        font-size: 16px;
      }
    }
  }
}
</style>
