<template>
  <div class="app-containers">
    <div class="containerBlock">
      <div class="top-actions">
        <div class="left-actions">
          <el-button size="small" @click="setVerticalLayout">上下结构</el-button>
          <el-button size="small" @click="setHorizontalLayout">左右结构</el-button>
          <el-button size="small" @click="handlePrevTrace">上一道</el-button>
          <el-button size="small" @click="handleNextTrace">下一道</el-button>
          <el-button type="primary" @click="submitSegyAnnotations">保存标注
            <i class="el-icon-check"></i>
          </el-button>
        </div>
        <!-- 右侧按钮组（与左侧同一行，靠右对齐） -->
        <div class="toolbar-right">
          <!--          <div class="color-maps">-->
          <!--            <el-select v-model="currentColorMap" @change="switchColorMap" size="small">-->
          <!--              <el-option v-for="map in colorMaps" :key="map.value" :label="map.label" :value="map.value">-->
          <!--                <span class="color-map-option">-->
          <!--                  <span class="color-map-preview" :class="map.value"></span>-->
          <!--                  {{ map.label }}-->
          <!--                </span>-->
          <!--              </el-option>-->
          <!--            </el-select>-->
          <!--          </div>-->
          <toolbar-controls :plots="plots" :data-loaded="isWidgetReady" :show-line-style-panel="showLineStylePanel"
                            @toggleLineStylePanel="toggleLineStylePanel" @exporting="exporting = $event"
                            @closePrintDialog="showPrintDialog = false" />

          <el-tooltip content="设置" placement="bottom" effect="light">
            <el-button @click="editProperties" :class="{ 'active': showLineStylePanel }">
              <i class="el-icon-setting"></i>
            </el-button>
          </el-tooltip>

          <el-tooltip content="绘制文本" placement="bottom" effect="light">
            <el-button @click="toggleDrawText" :class="{ 'active': isDrawingText }">
              <i class="el-icon-edit-outline"></i>
            </el-button>
          </el-tooltip>
          <el-tooltip content="绘制线条" placement="bottom" effect="light">
            <el-button @click="toggleLineStylePanel" :class="{ 'active': showLineStylePanel }">
              <i class="el-icon-edit"></i>
            </el-button>
          </el-tooltip>
          <el-tooltip content="保存标注" placement="bottom" effect="light">

          </el-tooltip>
          <!-- <el-tooltip :content="internalScrollbarSyncEnabled ? '内部滚动条同步已启用' : '内部滚动条同步已禁用'" placement="bottom"
            effect="light">
            <el-button @click="toggleInternalScrollbarSync" :class="{ 'active': internalScrollbarSyncEnabled }">
              <i class="el-icon-s-operation"></i>
            </el-button>
          </el-tooltip> -->
        </div>
        <!-- 缩略图   start-->
        <div v-if="shouldShowThumb" ref="thumbContainer" @click="handleThumbClick" @mousedown="startDrag"
             class="right-thumb draggable-thumb" :style="thumbPosition">
          <!-- <div class="thumb-title">缩略图</div> -->
          <div ref="thumbHolder" class="thumb-holder">
            <YsgcIndex v-if="thumbReady" :key="'thumb-' + routeId + '-' + thumbReady" :compact="true" :width="260"
                       :height="160" :id-override="routeId" :active-segy-index="currentSegyIndex" />
          </div>
          <!-- 拖动指示器 -->
          <div class="drag-handle">
            <i class="el-icon-rank"></i>
          </div>
        </div>
        <!-- 缩略图   end-->
        <!-- 缩略图弹窗 start -->
        <el-dialog v-if="shouldShowThumb" title="缩略图预览" :visible.sync="showThumbDialog" width="80%" append-to-body
                   :z-index="9999999" :modal="true" :close-on-click-modal="true" :close-on-press-escape="true"
                   custom-class="thumbnail-dialog">
          <div style="height: 100%;">
            <YsgcIndex :key="'dialog-thumb-' + routeId" :id-override="routeId" :active-segy-index="currentSegyIndex"
                       @segyLinePick="onThumbLinePick" />
          </div>
        </el-dialog>
        <!-- 缩略图弹窗 end -->
      </div>

      <!-- 添加加载状态和错误提示 -->
      <div v-if="loadingError" class="error-message">
        {{ loadingError }}
      </div>
      <div class="toolbar" v-if="isWidgetReady">
        <div class="toolbar-left">
        </div>
      </div>
      <div class="split-container" :class="layoutMode === 'vertical' ? 'layout-vertical' : 'layout-horizontal'"
           v-loading="isLoading" element-loading-text="加载中...">
        <div class="sync-section" ref="topScroll" @scroll="onScroll('top')">
          <div class="zoom-wrapper" ref="topWrapper"
               :style="{ width: baseCanvasWidth + 'px', height: baseCanvasHeight + 'px' }">
            <canvas ref="plot" id="canvasTop" class="plot-canvas" />
          </div>
        </div>
        <div class="sync-section" ref="bottomScroll" @scroll="onScroll('bottom')">
          <div class="zoom-wrapper" ref="bottomWrapper"
               :style="{ width: baseCanvasWidth + 'px', height: baseCanvasHeight + 'px' }">
            <canvas ref="plot2" id="canvasBottom" class="plot-canvas" />
          </div>
        </div>
      </div>
      <!-- 自定义右键菜单 -->
      <div v-if="contextMenu.visible" class="context-menu" :style="{
        left: `${contextMenu.x}px`,
        top: `${contextMenu.y}px`
      }" @mouseleave="hideContextMenu">
        <div v-for="(item, index) in contextMenuItems" :key="index">
          <div v-if="item.type === 'separator'" class="context-menu-separator">
          </div>
          <div v-else class="context-menu-item" :class="{ disabled: !isMenuItemEnabled(item.action) }"
               @click="handleMenuAction(item.action)">
            <span>
              <i :class="getElementIcon(item.icon)" class="mr-2"></i>
              {{ item.text }}
            </span>
            <span class="shortcut" v-if="item.shortcut">{{ item.shortcut }}</span>
          </div>
        </div>
      </div>
      <!-- 文本样式面板 -->
      <div class="style-panel text-style-panel" :class="{ 'style-panel-visible': showTextStylePanel }">
        <div class="style-panel-header">
          <h3>文本样式</h3>
          <el-button icon="el-icon-close" size="mini" circle @click="showTextStylePanel = false"></el-button>
        </div>
        <div class="style-content">
          <!-- 填充样式部分 -->
          <div class="style-section-title">填充样式</div>
          <div class="style-item">
            <span class="style-label">颜色：</span>
            <el-color-picker v-model="fillStyle.color" show-alpha @change="updateFillStyle">
            </el-color-picker>
          </div>
          <div class="style-item">
            <span class="style-label">样式：</span>
            <el-select v-model="fillStyle.pattern" placeholder="选择填充样式" @change="updateFillStyle">
              <el-option v-for="(pattern, key) in fillPatterns" :key="key" :label="key" :value="key">
                <div class="pattern-preview-fill" :style="getFillPatternStyle(key)"></div>
              </el-option>
            </el-select>
          </div>
          <div class="style-divider"></div>
          <!-- 线条样式部分 -->
          <div class="style-section-title">线条样式</div>
          <div class="style-item">
            <span class="style-label">颜色：</span>
            <el-color-picker v-model="lineStyle.color" show-alpha @change="updateLineStyle">
            </el-color-picker>
          </div>
          <div class="style-item">
            <span class="style-label">宽度：</span>
            <el-slider v-model="lineStyle.width" :min="1" :max="12" show-input @change="updateLineStyle">
            </el-slider>
          </div>
          <div class="style-item">
            <span class="style-label">样式：</span>
            <el-select v-model="lineStyle.pattern" placeholder="选择线条样式" @change="updateLineStyle">
              <el-option v-for="(pattern, key) in linePatterns" :key="key" :label="key" :value="key">
                <div class="pattern-preview-line" :style="getLinePatternStyle(key)"></div>
              </el-option>
            </el-select>
          </div>
          <!-- 分隔线 -->
          <div class="style-divider"></div>
          <div class="style-section-title">文本样式</div>
          <div class="style-item">
            <span class="style-label">颜色：</span>
            <el-color-picker v-model="textStyle.color" show-alpha @change="updateTextStyle">
            </el-color-picker>
          </div>
          <div class="style-item">
            <span class="style-label">大小：</span>
            <el-slider v-model="textStyle.size" :min="8" :max="60" show-input @change="handleFontSizeChange">
            </el-slider>
          </div>
          <div class="style-item">
            <span class="style-label">字体：</span>
            <el-select v-model="textStyle.font" placeholder="选择字体" @change="handleFontChange">
              <el-option v-for="(font, index) in Object.keys(TEXT_PATTERNS)" :key="index" :label="font" :value="font"
                         :style="{ fontFamily: font }">
                {{ font }}
              </el-option>
            </el-select>
          </div>
          <div class="style-item">
            <span class="style-label">对齐：</span>
            <div class="text-style-buttons">
              <el-button-group style="width: 100%">
                <el-button style="min-width: 20%; max-width: 20%" :type="textStyle.align === 'left' ? 'primary' : ''"
                           @click="textStyle.align = 'left'; updateTextStyle()" title="左对齐">
                  <i class="el-icon-s-fold"></i>
                </el-button>
                <el-button style="min-width: 20%; max-width: 20%" :type="textStyle.align === 'center' ? 'primary' : ''"
                           @click="textStyle.align = 'center'; updateTextStyle()" title="居中对齐">
                  <i class="el-icon-menu"></i>
                </el-button>
                <el-button style="min-width: 20%; max-width: 20%" :type="textStyle.align === 'right' ? 'primary' : ''"
                           @click="textStyle.align = 'right'; updateTextStyle()" title="右对齐">
                  <i class="el-icon-s-unfold"></i>
                </el-button>
                <!-- 粗体按钮 -->
                <el-button style="min-width: 20%; max-width: 20%" :type="textStyle.bold ? 'primary' : ''"
                           @click="textStyle.bold = !textStyle.bold; updateTextStyle()" title="粗体">
                  <span style="font-weight: bold">B</span>
                </el-button>
                <!-- 斜体按钮 -->
                <el-button style="min-width: 20%; max-width: 20%" :type="textStyle.italic ? 'primary' : ''"
                           @click="textStyle.italic = !textStyle.italic; updateTextStyle()" title="斜体">
                  <span style="font-style: italic">I</span>
                </el-button>
              </el-button-group>
            </div>
          </div>
          <!-- 添加属性部分 -->
          <div class="style-divider"></div>
          <div class="style-section-title">属性</div>
          <div class="style-item">
            <span class="style-label">边框圆角：</span>
            <el-input-number v-model="textStyle.borderRadius" :min="0" :max="30" size="small"
                             @change="handleBorderRadiusChange">
            </el-input-number>
          </div>
          <div class="style-item">
            <el-checkbox v-model="textStyle.fixedFont" @change="handleFixedFontChange">
              固定字体
            </el-checkbox>
          </div>
        </div>
      </div>
      <!-- 线条样式面板 -->
      <div class="style-panel line-style-panel" :class="{ 'style-panel-visible': showLineStylePanel }">
        <div class="style-panel-header">
          <h3>线条样式</h3>
          <el-button icon="el-icon-close" size="mini" circle @click="showLineStylePanel = false"></el-button>
        </div>
        <div class="style-content">
          <div class="style-item">
            <span class="style-label">颜色：</span>
            <el-color-picker v-model="lineStyle.color" show-alpha @change="updateLineStyle">
            </el-color-picker>
          </div>
          <div class="style-item">
            <span class="style-label">样式：</span>
            <el-select v-model="lineStyle.pattern" placeholder="选择线条样式" @change="updateLineStyle">
              <el-option v-for="(pattern, key) in linePatterns" :key="key" :label="key" :value="key">
                <div class="pattern-preview-line" :style="getLinePatternStyle(key)"></div>
              </el-option>
            </el-select>
          </div>
          <div class="style-item">
            <span class="style-label">宽度：</span>
            <el-slider v-model="lineStyle.width" :min="1" :max="12" show-input @change="updateLineStyle">
            </el-slider>
          </div>
        </div>
      </div>
    </div>


    <!--    图形设置-->
    <el-dialog title="设置" :visible.sync="showPropertiesDialog" width="100%">
      <el-form ref="form" label-width="130px">
        <el-row>

          <el-col :span="5">
            <el-form-item label="颜色集合">
              <el-select v-model="colorMapSelect" placeholder="请选择颜色集合" @change="changeColor">
                <el-option v-for="item in listNameColorMaps" :label="item" :value="item"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="归一化类型">
              <el-select v-model="NormalizationType" @change="changeNor" placeholder="请选择归一化类型">
                <el-option v-for="item in NormalizationTypeData" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="归一化比例">
              <el-slider @change="changeNor" style="width: 180px;" v-model="NormalizationBl" :min="0.1" :max="5"
                         :step="0.1" show-stops>
              </el-slider>
            </el-form-item>
          </el-col>
          <!--          <el-col :span="5">-->
          <!--            <el-form-item label="每英寸道数" >-->
          <!--              <el-input v-model="mycds" @blur="changeMycds"></el-input>-->
          <!--            </el-form-item>-->
          <!--          </el-col>-->

        </el-row>
        <el-row>
          <!--          <el-col :span="5">-->
          <!--            <el-form-item label="每秒英寸数" >-->
          <!--              <el-input v-model="msycs" @blur="changeMycds"></el-input>-->
          <!--            </el-form-item>-->
          <!--          </el-col>-->
          <el-col :span="5">
            <el-form-item label="采样插值类型">
              <el-select v-model="samplesType" @change="changeInt" placeholder="请选择采样插值类型">
                <el-option v-for="item in InterpolationType" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="采样插值边缘">
              <el-select v-model="samplesEdge" @change="changeInt" placeholder="请选择采样插值边缘">
                <el-option v-for="item in InterpolationEdge" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="道插值类型">
              <el-select v-model="tracesEdge" @change="changeInt" placeholder="请选择道插值类型">
                <el-option v-for="item in InterpolationType" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="5">
            <el-form-item label="道插值边缘">
              <el-select v-model="tracesType" @change="changeInt" placeholder="请选择道插值边缘">
                <el-option v-for="item in InterpolationEdge" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="10">
            <el-form-item label="绘图类型">
              <el-checkbox v-model="Wiggle" @change="changePlotType">Wiggle</el-checkbox>
              <el-checkbox v-model="Reversed" @change="changePlotType">Reversed</el-checkbox>
              <el-checkbox v-model="PositiveFill" @change="changePlotType">Positive fill</el-checkbox>
              <el-checkbox v-model="NegativeFill" @change="changePlotType">Negative fill</el-checkbox>
              <el-checkbox v-model="PositiveColorFill" @change="changePlotType">Positive color fill</el-checkbox>
              <el-checkbox v-model="NegativeColorFill" @change="changePlotType">Negative color fill</el-checkbox>
              <el-checkbox v-model="SimpleDensity" @change="changePlotType">Simple density</el-checkbox>
              <el-checkbox v-model="InterpolatedDensity" @change="changePlotType">Interpolated density</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="Wiggle-裁剪因子">
              <el-input v-model="ClippingFactor" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="5">
            <el-form-item label="Wiggle-抽取间距">
              <el-input v-model="DecimationSpacing" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="Wiggle-密度抽取">
              <el-checkbox v-model="densityDecimation" @change="changePlotType">Density decimation（密度抽取）</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="5">
            <el-form-item label="Clipping mode（裁剪模式）">
              <el-select v-model="ClippingMode" @change="changePlotType" placeholder="请选择裁剪模式">
                <el-option v-for="item in ClippingModeData" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
        <el-row>
          <el-col :span="3">
            <el-form-item label="TaperFilter（滤波）">
              <el-checkbox v-model="TaperFilterEnbled" @change="changePlotType">启用滤波</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item label="f1">
              <el-input v-model="f1" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item label="f2">
              <el-input v-model="f2" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item label="f3">
              <el-input v-model="f3" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="2">
            <el-form-item label="f4">
              <el-input v-model="f4" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="4">
            <el-form-item label="采样率">
              <el-input v-model="sampleRate" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="带通模式">
              <el-checkbox v-model="passFlag" @change="changePlotType">带通模式</el-checkbox>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row>
          <el-col :span="3">
            <el-form-item label="AGC">
              <el-checkbox v-model="AGCEnbled" @change="changePlotType">启用AGC</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="AGC length">
              <el-input v-model="AGCLength" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Desired average">
              <el-input v-model="DesiredAverage" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Noise reduction">
              <el-select v-model="NoiseReduction" @change="changePlotType" placeholder="请选择降噪">
                <el-option v-for="item in NoiseReductionData" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Noise reduction percentage">
              <el-input v-model="NoiseReductionPercentage" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Start sample">
              <el-input v-model="StartSample" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Step">
              <el-input v-model="Step" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>

        </el-row>
        <el-row>
          <el-col :span="4">
            <el-form-item label="Units">
              <el-select v-model="Units" @change="changePlotType" placeholder="请选择单位">
                <el-option v-for="item in UnitsData" :label="item.label" :value="item.value"></el-option>
              </el-select>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="Window length">
              <el-input v-model="WindowLength" style="width: 80px" @blur="changePlotType"></el-input>
            </el-form-item>
          </el-col>
        </el-row>

        <el-row>
          <el-col :span="3">
            <el-form-item label="Reverse">
              <el-checkbox v-model="ReverseEnbled" @change="changePlotType">启用Reverse</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="inverted">
              <el-checkbox v-model="inverted" @change="changePlotType">启用inverted</el-checkbox>
            </el-form-item>
          </el-col>
          <el-col :span="3">
            <el-form-item label="reversed">
              <el-checkbox v-model="reversed" @change="changePlotType">启用reversed</el-checkbox>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="showPropertiesDialog = false">取 消</el-button>
        <el-button type="primary" @click="showPropertiesDialog = false">确 定</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
import { SeismicWidget } from '@int/geotoolkit/seismic/widgets/SeismicWidget';
import { SeismicColors } from '@int/geotoolkit/seismic/util/SeismicColors';
import { SeismicPipeline } from '@int/geotoolkit/seismic/pipeline/SeismicPipeline';
import { SegyReader } from '@int/geotoolkit/seismic/data/SegyReader';
import { LocalFile } from '@int/geotoolkit/seismic/data/LocalFile';
import { Plot } from '@int/geotoolkit/plot/Plot';
import { getToken } from '@/utils/auth';
import { Group } from '@int/geotoolkit/scene/Group';
import { Paint } from '@int/geotoolkit/controls/tools/Paint';
import { PaintMode } from '@int/geotoolkit/controls/tools/PaintMode';
import { EditEvents } from '@int/geotoolkit/controls/tools/EditEvents';
import { EditMode } from '@int/geotoolkit/controls/tools/EditMode';
import { Selection, Events as SelectionEvents } from '@int/geotoolkit/controls/tools/Selection';
import { TextStyle } from '@int/geotoolkit/attributes/TextStyle';
import { LineStyle } from '@int/geotoolkit/attributes/LineStyle';
import { FillStyle } from '@int/geotoolkit/attributes/FillStyle';
import { Text } from '@int/geotoolkit/scene/shapes/Text';
import { NormalizationType } from '@int/geotoolkit/seismic/pipeline/NormalizationType';
import { NoSnapPicking } from '@int/geotoolkit/seismic/data/snap/NoSnapPicking';
import { SnapPicker } from '@int/geotoolkit/seismic/data/snap/SnapPicker';
import { ColorBarLocation } from '@int/geotoolkit/controls/shapes/ColorBarLocation';
import { Alignment as BoxLayoutAlignment } from '@int/geotoolkit/layout/BoxLayout';
import { LINE_PATTERNS, FILL_PATTERNS, TEXT_PATTERNS, LINESTYLE_PATTERNS, IMAGE_PATTERNS, LS_KEYS, FS_KEYS, TS_KEYS } from '@/api/Patterns.js';
import { SizeMode } from '@int/geotoolkit/scene/shapes/Text';
import { RgbaColor } from '@int/geotoolkit/util/RgbaColor';
import { AutoNumberFormat } from '@int/geotoolkit/util/AutoNumberFormat';
// 导入新的组件
import ToolbarControls from '@/components/ToolbarControls.vue';
import YsgcIndex from './index.vue';
import LineStylePanel from '@/components/LineStylePanel.vue';
import { CrossHair, Events as CrossHairEvents } from '@int/geotoolkit/controls/tools/CrossHair';
import { TaperFilterProcess } from '@int/geotoolkit/seismic/analysis/filters/TaperFilterProcess';
import { AGC } from '@int/geotoolkit/seismic/pipeline/processor/AGC';
import { Reverse } from '@int/geotoolkit/seismic/pipeline/processor/Reverse';
import { Path } from '@int/geotoolkit/scene/shapes/Path';
import * as echarts from 'echarts';
import { toDht } from '@/api/ysqqXmxx/ysqqXmxx';
import { addAll as addAllSegyDz } from '@/api/ysqqXmxxSegydz/segydz'

// 线条样式模式常量
const TEXT_PATTERN_KEYS = Object.keys(TEXT_PATTERNS);
const FILL_PATTERN_KEYS = Object.keys(FILL_PATTERNS);
const LINE_PATTERN_KEYS = Object.keys(LINE_PATTERNS);

// 在export default前添加interpolate函数
const interpolate = function (target, startIndex, endIndex, startColor, endColor) {
  // 添加参数验证
  if (!target || !Array.isArray(target)) {
    console.error('interpolate: target必须是数组');
    return;
  }

  if (typeof startIndex !== 'number' || typeof endIndex !== 'number' ||
    startIndex < 0 || endIndex >= target.length || startIndex > endIndex) {
    console.error(`interpolate: 索引无效 - startIndex: ${startIndex}, endIndex: ${endIndex}, target.length: ${target.length}`);
    return;
  }

  if (!startColor || !endColor ||
    typeof startColor.R !== 'number' || typeof startColor.G !== 'number' || typeof startColor.B !== 'number' ||
    typeof endColor.R !== 'number' || typeof endColor.G !== 'number' || typeof endColor.B !== 'number') {
    console.error('interpolate: 颜色必须包含有效的RGB值');
    return;
  }

  const offset = startIndex;
  const stop = (endIndex - startIndex);
  let r, g, b;

  const stepR = (endColor.R - startColor.R) / (stop);
  const stepG = (endColor.G - startColor.G) / (stop);
  const stepB = (endColor.B - startColor.B) / (stop);

  try {
    for (let i = 0; i <= stop; ++i) {
      r = startColor.R + i * stepR;
      g = startColor.G + i * stepG;
      b = startColor.B + i * stepB;
      target[offset + i] = new RgbaColor(
        Math.round(r < 255 ? r : 255),
        Math.round(g < 255 ? g : 255),
        Math.round(b < 255 ? b : 255),
        255
      );
    }
  } catch (error) {
    console.error(`interpolate: 创建颜色时出错 - ${error.message}`);
  }
};
export default {
  name: "YsgcIndex2",
  components: {
    ToolbarControls,
    LineStylePanel,
    YsgcIndex
  },
  data() {
    return {
      // 布局模式：vertical 上下结构；horizontal 左右结构
      layoutMode: 'vertical',
      // 缩略图（ECharts）
      thumbChart: null,
      thumbResizeObserver: null,
      thumbPoints: [],
      thumbLines: [],
      thumbBounds: { xMin: null, xMax: null, yMin: null, yMax: null },
      thumbId: null,
      // segy导航相关
      segyList: [], // 存储所有segy数据
      ysqqXmxxSegy: [], // 保存 toDht 返回的 ysqqXmxxSegy 原始数组
      currentSegyIndex: 0, // 当前segy索引
      plots: null,
      plotsBottom: null,
      _seismicWidget: null,
      _seismicWidgetBottom: null,
      pipeline: null,
      pipelineBottom: null,
      // zoom & scroll sync
      zoomScale: 1,
      baseCanvasHeight: 800,
      baseCanvasWidth: 1200,
      _isSyncingScroll: false,
      _scrollSyncTimeout: null, // 滚动同步超时保护
      _zoomHooked: false,
      _isSyncingZoom: false,
      _isInitialLoad: true, // 添加初始加载标志
      isHovering: false,
      cursorInfo: {
        depth: null,
        trace: null,
        value: null
      },
      showCursorInfo: true,
      isWidgetReady: false,
      isLoading: false,
      loadingError: null,
      _headers: [],
      _colorMap: null,
      // 顶部/底部分别维护标注缓存与还原数据
      savedAnnotations: [],
      savedLineAnnotations: [],
      savedAnnotationsBottom: [],
      savedLineAnnotationsBottom: [],
      collectedAnnotations: [], // 实时采集缓存（将带有 panel 标记）
      // savedLineAnnotations: [{
      //   properties: {
      //     x: [2390.510986101919, 2313.4866975512905, 2307.7161482461947, 2303.4509596293847, 2298.934877564527,
      //         2295.924156187955, 2292.9134348113835, 2290.404500330907, 2287.8955658504306, 2283.63037723362,
      //         2280.870549305096, 2278.612508272667, 2275.852680344143, 2274.347319655857, 2272.8419589675714,
      //         2271.8383851753806, 2271.8383851753806, 2272.340172071476, 2273.092852415619, 2274.8491065519524,
      //         2276.8562541363335, 2280.3687624090007, 2287.6446724023826, 2292.6625413633355, 2298.4330906684318,
      //         2307.2143613500994, 2313.7375909993384, 2320.511714096625, 2325.7804765056253, 2333.307279947055,
      //         2344.095698213104, 2349.8662475182, 2356.1385837193916, 2365.421641297154, 2373.450231634679,
      //         2382.231502316347, 2389.7583057577763, 2403.3065519523498, 2422.625347452019, 2433.915552614163,
      //         2443.1986101919256, 2449.470946393117, 2457.75043017869, 2469.5424222369293, 2475.8147584381204,
      //         2488.861217736598, 2508.6818001323627, 2522.731833223031, 2536.530972865652, 2547.0684976836533,
      //         2628.1070814030445],
      //     y: [2.5366336633663367, 2.5056105610561055, 2.506930693069307, 2.5095709570957094, 2.516831683168317,
      //         2.5227722772277223, 2.5346534653465347, 2.545214521452145, 2.5597359735973595, 2.586138613861386,
      //         2.6046204620462046, 2.625082508250825, 2.6547854785478546, 2.6785478547854784, 2.707590759075907,
      //         2.7326732673267324, 2.758415841584158, 2.801980198019802, 2.834983498349835, 2.8666666666666667,
      //         2.89042904290429, 2.925412541254125, 2.9788778877887787, 3.0072607260726074, 3.0323432343234322,
      //         3.0613861386138614, 3.0792079207920793, 3.094389438943894, 3.104290429042904, 3.1135313531353135,
      //         3.124092409240924, 3.1273927392739274, 3.13003300330033, 3.130693069306931, 3.131353135313531,
      //         3.131353135313531, 3.131353135313531, 3.132673267326733, 3.1353135313531353, 3.1366336633663363,
      //         3.1372937293729373, 3.137953795379538, 3.1392739273927392, 3.141254125412541, 3.141254125412541,
      //         3.1399339933993398, 3.1392739273927392, 3.1392739273927392, 3.1392739273927392, 3.1392739273927392,
      //         3.1392739273927392],
      //     linestyle: {
      //       Lx: "#0351ad",
      //       fA: 2
      //     }
      //   },
      //   bounds: {
      //     x: 2271.8383851753806,
      //     y: 2.5056105610561055,
      //     width: 356.2686962276639,
      //     height: 0.6356435643564353
      //   }
      // }],
      // Add missing reactive properties
      showLineStylePanel: false,
      showTextStylePanel: false,
      isDrawingText: false,
      savedAnnotations: [],
      // 添加模拟数据
      // savedAnnotations: [{
      //   type: "unknown",
      //   text: "发发发",
      //   properties: {
      //     id: null,
      //     name: "",
      //     cssclass: null,
      //     selectable: true,
      //     visible: true,
      //     tag: null,
      //     localtransform: null,
      //     clipstyle: null,
      //     responsivestyle: null,
      //     renderingfilter: null,
      //     scalescrollstrategy: {},
      //     linestyle: {
      //       links: {
      //         Invalidate: {
      //           yn: new Array(45).fill(null),
      //           stack: 0,
      //           gDa: false
      //         }
      //       },
      //       silent: false,
      //       u3: false,
      //       uL: 45,
      //       Ek: 1,
      //       Lx: "#0351ad",
      //       Zr: null,
      //       Jeb: null,
      //       xVa: [],
      //       fA: 2,
      //       Ewa: {
      //         x: false,
      //         y: false
      //       },
      //       XGa: "round",
      //       UGa: "butt",
      //       Cs: null,
      //       Td: null
      //     },
      //     fillstyle: {
      //       links: {
      //         Invalidate: {
      //           yn: new Array(45).fill(null),
      //           stack: 0,
      //           gDa: false
      //         }
      //       },
      //       silent: false,
      //       u3: false,
      //       uL: 45,
      //       Ek: 0,
      //       Lx: "#c7e1f6",
      //       Zr: null,
      //       Jeb: null,
      //       iO: false,
      //       zk: null
      //     },
      //     ax: 2408.8262078093985,
      //     ay: 0.7689768976897691,
      //     width: 66,
      //     height: 22,
      //     rotationangle: 0,
      //     alignment: 5,
      //     sizeisindevicespace: true,
      //     preserveaspectratio: false,
      //     ispointingup: true,
      //     preservereadingorientation: true,
      //     preserverightangle: true,
      //     useminmaxdimensions: false,
      //     mindimension: null,
      //     maxdimension: null,
      //     layoutstyle: null,
      //     text: "发发发",
      //     textstyle: {
      //       links: {
      //         Invalidate: {
      //           yn: [null],
      //           stack: 0,
      //           gDa: false
      //         }
      //       },
      //       silent: false,
      //       u3: false,
      //       uL: 1,
      //       Ek: 0,
      //       Lx: "#000000",
      //       Zr: null,
      //       Jeb: null,
      //       lH: "22px Sans-serif",
      //       Cua: "middle",
      //       Vf: "left",
      //       y9: "100%",
      //       hS: true,
      //       E2: true,
      //       ofa: {
      //         fontweight: "normal",
      //         fontsize: "22px",
      //         fontfamily: "Sans-serif",
      //         fontlineheight: "normal",
      //         fontstyle: "normal"
      //       },
      //       Km: null,
      //       iGa: "Sans-serif",
      //       eZ: "22px",
      //       c3: "normal",
      //       b3: "normal"
      //     },
      //     bounds: {
      //       readOnly: true,
      //       x: 2326.031369953673,
      //       y: 0.6963696369636965,
      //       width: 165.58967571144967,
      //       height: 0.1452145214521452
      //     },
      //     layout: {
      //       readOnly: false,
      //       x: 0,
      //       y: 0,
      //       width: 66,
      //       height: 22
      //     },
      //     sizemode: 5,
      //     userheight: 30.00000000000003,
      //     userwidth: 99.99999999999989,
      //     radius: 10,
      //     padding: 0,
      //     transform: "none",
      //     ellipsisstring: "..."
      //   },
      //   bounds: {
      //     readOnly: true,
      //     x: 2326.031369953673,
      //     y: 0.6963696369636965,
      //     width: 165.58967571144967,
      //     height: 0.1452145214521452
      //   }
      // }],
      // 添加鼠标悬停相关的数据
      cursorInfo: {
        depth: null,
        trace: null,
        value: null
      },
      showCursorInfo: true,
      isHovering: false,
      // 添加画笔工具相关属性
      pencilTool: null,
      selectedShape: null,
      selectedShapes: [],
      annotationLayer: null,
      pencilState: {
        isDrawing: false,
        currentPath: null,
        lastPoint: null,
        paths: []
      },
      pencilConfig: {
        minDistance: 2,  // 减小最小距离使绘制更流畅
        lineWidth: 2,
        lineColor: '#0351ad',
        linePattern: 'Solid'
      },
      // 更新颜色映射选择器
      currentColorMap: 'WhiteBlack', // 默认使用黑白渐变
      colorMaps: [
        { value: 'WhiteBlack', label: '黑白渐变' },
        { value: 'CustomGrayScale', label: '灰度渐变' },
        { value: 'CustomRedScale', label: '红色渐变' },
        { value: 'BlueWhiteRed', label: '蓝白红渐变' },
        // { value: 'Rainbow', label: '彩虹渐变' },
        // { value: 'Jet', label: 'Jet渐变' },
        // { value: 'Hot', label: '热力图' },
        // { value: 'Cool', label: '冷色图' }
      ], // 可用的颜色映射
      textStyle: {
        color: '#000000',
        size: 22,
        font: 'Sans-serif',
        bold: false,
        italic: false,
        align: 'left',
        wrap: true,
        ellipsis: true,
        borderRadius: 10,
        fixedFont: false,
      },
      lineStyle: {
        color: '#0351ad',
        width: 2,
        pattern: 'Solid'
      },
      fillStyle: {
        color: '#c7e1f6',
        pattern: 'Solid',
        opacity: 100
      },
      fillPatterns: IMAGE_PATTERNS,
      TEXT_PATTERNS: TEXT_PATTERNS,
      FILL_PATTERNS: FILL_PATTERNS,
      LINE_PATTERNS: LINE_PATTERNS,
      LINESTYLE_PATTERNS: LINESTYLE_PATTERNS,
      linePatterns: LINESTYLE_PATTERNS,
      initialLineStyle: null,
      initialTextStyle: null,
      initialFillStyle: null,
      textPatterns: {
        'None': [0, 10],
        'Solid': [],
        'Dash': [20, 4],
        'Dot': [2, 4],
        'DashDot': [20, 4, 2, 4],
        'DashDotDot': [20, 4, 2, 4, 2, 4]
      },
      isWidgetReady: false,
      loadingError: null,
      pipeline: null,
      colorProvider: null,
      // 右键菜单相关数据
      contextMenu: {
        visible: false,
        x: 0,
        y: 0
      },
      _contextMenuClickBound: false, // 标记 document click 事件是否已绑定
      contextMenuItems: [
        {
          text: '撤销',
          icon: 'mdi-undo',
          shortcut: 'Ctrl+Z',
          action: 'undo'
        },
        {
          text: '重做',
          icon: 'mdi-redo',
          shortcut: 'Ctrl+Y',
          action: 'redo'
        },
        { type: 'separator' },
        {
          text: '复制',
          icon: 'mdi-content-copy',
          shortcut: 'Ctrl+C',
          action: 'copy'
        },
        {
          text: '粘贴',
          icon: 'mdi-content-paste',
          shortcut: 'Ctrl+V',
          action: 'paste'
        },
        {
          text: '删除',
          icon: 'mdi-delete',
          shortcut: 'Del',
          action: 'delete'
        }
      ],
      clipboard: null, // 用于存储复制的路径
      undoStack: [], // 撤销栈
      redoStack: [], // 重做栈
      internalScrollbarSyncEnabled: true, // 默认启用内部滚动条同步
      _isSyncingInternalScroll: false, // 防止内部滚动条同步循环
      _isSyncingOuterScroll: false, // 防止外层滚动条同步循环
      _outerScrollListeners: [], // 外层滚动条监听器数组
      _outerScrollbarSyncInterval: null, // 外层滚动条同步监控定时器
      _isSyncingDOMScroll: false, // 防止DOM滚动条同步循环
      _domScrollListeners: [], // DOM滚动条监听器列表
      _lastTopScrollLeft: 0, // 记录顶部滚动条水平位置
      _lastTopScrollTop: 0, // 记录顶部滚动条垂直位置
      _lastBottomScrollLeft: 0, // 记录底部滚动条水平位置
      _lastBottomScrollTop: 0, // 记录底部滚动条垂直位置
      thumbReady: false,
      showThumbDialog: false, // 缩略图大图弹窗可见性
      // 是否允许在未指定项目/无接口数据时加载示例数据
      shouldLoadDemo: true,
      // 缩略图拖动相关
      isDragging: false,
      dragStartX: 0,
      dragStartY: 0,
      dragDistance: 0,
      dragThreshold: 5, // 拖动阈值，超过这个距离才算拖动
      thumbPosition: {
        top: '150px',
        right: '20px',
        left: 'auto',
        bottom: 'auto'
      },


      //  图形设置
      showPropertiesDialog: false,
      listNameColorMaps: [
        "WhiteBlack",
        "RedWhiteBlack",
        "RedWhiteBlue",
        "Saddleback",
        "Angles5color",
        "BlackRedYellowWhite",
        "GreyOrange",
        "IntervalVelocity",
        "IntervalVelocity16",
        "IntervalVelocity32",
        "Rainbow",
        "RedGreenBlue",
        "RedWhiteBlueExtremes",
        "RedWhiteBlueHot",
        "RedYellowBlue",
        "SaddlebackHot",
        "Spectrum"
      ],
      colorMapSelect: "",
      // _colorMap: "",
      // pipeline: null,
      // _seismicWidget: null,
      NormalizationType: null,
      NormalizationBl: 0.1,
      NormalizationTypeData: [
        {
          "label": "None",
          "value": 0,
        },
        {
          "label": "Maximum",
          "value": 1,
        },
        {
          "label": "TraceMaximum",
          "value": 2,
        },
        {
          "label": "Average",
          "value": 3,
        },
        {
          "label": "TraceAverage",
          "value": 4,
        }, {
          "label": "RMS",
          "value": 5,
        }, {
          "label": "TraceRMS",
          "value": 6,
        }, {
          "label": "Limits",
          "value": 7,
        }
      ],
      mycds: null,
      msycs: null,
      samplesType: null,
      samplesEdge: null,
      tracesType: null,
      tracesEdge: null,
      InterpolationType: [
        {
          "label": "Linear",
          "value": 1,
        }, {
          "label": "Quadratic",
          "value": 2,
        }, {
          "label": "Step",
          "value": 3,
        }, {
          "label": "CenteredStep",
          "value": 4,
        }, {
          "label": "Cubic",
          "value": 5,
        }, {
          "label": "Logarithmic",
          "value": 6,
        },
      ],
      InterpolationEdge: [
        {
          "label": "Zero",
          "value": 0,
        }, {
          "label": "Duplicate",
          "value": 1,
        }
      ],
      Wiggle: false,
      Reversed: false,
      PositiveFill: false,
      NegativeFill: false,
      PositiveColorFill: false,
      NegativeColorFill: false,
      SimpleDensity: false,
      InterpolatedDensity: true,
      ClippingFactor: 4,
      DecimationSpacing: 5,
      densityDecimation: false,
      ClippingMode: null,
      ClippingModeData: [
        {
          "label": "Connected",
          "value": "Connected"
        }, {
          "label": "Disconnected",
          "value": "Disconnected"
        },
      ],
      TaperFilterEnbled: false,
      f1: 10,
      f2: 20,
      f3: 60,
      f4: 70,
      sampleRate: 0,
      passFlag: false,
      AGCEnbled: false,
      AGCLength: 0,
      DesiredAverage: 1,
      NoiseReductionPercentage: 3,
      NoiseReduction: null,
      StartSample: 0,
      Step: 1,
      Units: "",
      WindowLength: 250,
      UnitsData: [
        {
          "label": "Sample",
          "value": 0
        }, {
          "label": "Time",
          "value": 1
        },
      ],
      NoiseReductionData: [
        {
          "label": "disable",
          "value": "disable"
        }, {
          "label": "enable",
          "value": "enable"
        }, {
          "label": "auto",
          "value": "auto"
        },
      ],

      ReverseEnbled: false,
      inverted: false,
      reversed: false,
    };
  },
  computed: {
    routeId() {
      try {
        const route = this.$route || {};
        const params = route.params || {};
        const query = route.query || {};
        return params.zbid || query.zbid || params.id || query.id || this.thumbId || null;
      } catch (e) {
        return this.thumbId || null;
      }
    },
    shouldShowThumb() {
      // 只在当前页面显示缩略图，通过路由路径判断
      try {
        const route = this.$route || {};
        const path = route.path || '';
        // 如果路径包含 'ysgc' 或者 'index2'，则显示缩略图
        return path.includes('ysgc') || path.includes('index2');
      } catch (e) {
        return false;
      }
    }
  },
  watch: {
    // 监听 currentSegyIndex 变化
    currentSegyIndex(newVal, oldVal) {
      console.log('[index2] currentSegyIndex 变化:', {
        oldVal,
        newVal,
        segyListLength: this.segyList ? this.segyList.length : 0
      })
    },
    // 监听路由变化，当路由参数改变时重新初始化数据
    '$route'(to, from) {
      //console.log('[index2] 路由变化:', to.query, from.query);
      // 如果路由参数发生变化，重新初始化组件
      if (to.query.id !== from.query.id || to.query.zbid !== from.query.zbid) {
        this.handleRouteChange();
      }
    },
    // 监听routeId变化
    routeId(newId, oldId) {
      //console.log('[index2] routeId变化:', newId, oldId);
      if (newId !== oldId) {
        this.handleRouteChange();
        // 强制刷新缩略图
        this.forceRefreshThumb();
      }
    }
  },
  mounted() {
    // 初始化时强制设置为初始状态
    this.resetToInitialState();

    // 立即禁用滚动条工具
    this.disableScrollbarTools();

    // 添加强制隐藏滚动条的CSS
    this.addForceHideScrollbarCSS();

    // 关闭强力滚动条监控，避免影响全局布局
    // this.startAggressiveScrollbarMonitor();

    this.$nextTick(async () => {
      ['thumb-test-container', 'thumb-chart-container', 'super-visible-thumb'].forEach(id => {
        const el = document.getElementById(id);
        if (el) try { el.remove(); } catch (e) { }
      });
      // 保持缩略图容器在组件内部，避免在DOM树中难以定位
      // 初始化场景时不自动加载演示数据，等待接口结果决定
      this.shouldLoadDemo = false;
      this.createScene(this.$refs.plot, { autoloadDemo: false });
      // 等DOM稳定后再渲染缩略图组件
      setTimeout(() => {
        this.thumbReady = true;
        // 再兜底：确保右上角出现内容，并直接绘制缩略图
        setTimeout(() => {
          this.ensureThumbRendered();
          this.drawThumbDirect();
        }, 200);
      }, 100);
      // 已改为内嵌 YsgcIndex 缩略图，不再走旧的 ECharts 缩略图初始化

      // 自动拉取接口数据并加载第一组上/下部 SEGY（jbsegy -> 顶部，xbsegy -> 底部）
      try {
        await this.loadThumbData();
        if (Array.isArray(this.segyList) && this.segyList.length > 0) {
          await this.loadCurrentSegy();
        } else {
          // 无接口数据：若没有路由id，允许加载演示数据；若有id但无数据，保持空白
          const hasId = !!this.routeId;
          if (!hasId) {
            this.shouldLoadDemo = true;
            try { await this.handleFileSelect(this.plots); } catch (e) { }
          } else {
            this.clearCurrentPlots();
            console.info('[index2] 该项目无可用SEGY数据');
          }
        }
      } catch (e) {
        console.warn('[index2] 自动加载数据失败:', e);
        // 加载失败时，如果没有路由ID，尝试加载演示数据
        if (!this.routeId) {
          this.shouldLoadDemo = true;
          try { await this.handleFileSelect(this.plots); } catch (e) { }
        }
      }
    });
  },
  mounted() {
    // 将缩略图容器移动到body，确保fixed基于视口
    if (this.$refs.thumbContainer && this.$refs.thumbContainer.parentNode !== document.body) {
      document.body.appendChild(this.$refs.thumbContainer);
    }
    this.createScene(this.$refs.plot);

    // 在 createScene 之后绑定右键菜单事件监听器
    this.$nextTick(() => {
      this.bindContextMenuListeners();
    });

    // 等DOM稳定后再渲染缩略图组件
    setTimeout(() => {
      this.thumbReady = true;
      // 再兜底：确保右上角出现内容，并直接绘制缩略图
      setTimeout(() => {
        this.ensureThumbRendered();
      }, 200);
    }, 100);

    //console.log('测试函数已添加:');
    //console.log('- window.testOuterScrollbarSync() - 测试外层滚动条同步');
    //console.log('- window.testInternalScrollbarHidden() - 测试内部滚动条隐藏');
  },
  beforeDestroy() {
    // 移除右键菜单事件监听
    if (this.$refs.plot) {
      this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
    }
    if (this.$refs.plot2) {
      this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
    }
    document.removeEventListener('click', this.hideContextMenu);

    // 清理拖动事件监听
    document.removeEventListener('mousemove', this.onDrag);
    document.removeEventListener('mouseup', this.stopDrag);
    // 移除键盘事件监听
    document.removeEventListener('keydown', this.handleKeyDown);
    // 移除窗口变化监听
    window.removeEventListener('resize', this.updateBaseCanvasSize);
  },
  methods: {
    // 深度序列化 properties 对象，将复杂对象转换为可序列化的格式
    serializeProperties(props) {
      if (!props || typeof props !== 'object') return {}
      const result = {}
      try {
        for (const key in props) {
          if (!props.hasOwnProperty(key)) continue
          const value = props[key]
          // 跳过函数和 undefined
          if (typeof value === 'function' || value === undefined) continue

          // 特殊处理 text 字段 - 确保文本内容被正确保留
          if (key === 'text') {
            if (value !== null && value !== undefined) {
              const textValue = String(value)
              // 即使文本为空字符串，也保留它（因为可能是用户有意设置的）
              result[key] = textValue
              continue
            } else {
              result[key] = null
              continue
            }
          }

          // 处理 null
          if (value === null) {
            result[key] = null
            continue
          }
          // 处理基本类型
          if (typeof value !== 'object') {
            result[key] = value
            continue
          }
          // 处理数组
          if (Array.isArray(value)) {
            result[key] = value.map(item => {
              if (typeof item === 'object' && item !== null) {
                return this.serializeProperties(item)
              }
              return item
            })
            continue
          }
          // 处理复杂对象 - 尝试提取可序列化的属性
          try {
            // 如果对象有常见的方法，尝试调用它们获取值
            const serialized = this.serializeProperties(value)
            if (value.getColor && typeof value.getColor === 'function') {
              try {
                serialized.color = value.getColor()
              } catch (e) { }
            }
            if (value.getFont && typeof value.getFont === 'function') {
              try {
                serialized.font = value.getFont()
              } catch (e) { }
            }
            if (value.getAlignment && typeof value.getAlignment === 'function') {
              try {
                serialized.alignment = value.getAlignment()
              } catch (e) { }
            }
            result[key] = serialized
          } catch (e) {
            // 如果序列化失败，尝试 JSON.stringify/parse 来提取可序列化的部分
            try {
              const str = JSON.stringify(value)
              result[key] = JSON.parse(str)
            } catch (e2) {
              // 如果都失败，记录对象的所有可枚举属性
              const simpleObj = {}
              for (const k in value) {
                if (value.hasOwnProperty(k)) {
                  const v = value[k]
                  if (typeof v !== 'function' && v !== undefined) {
                    if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
                      simpleObj[k] = this.serializeProperties(v)
                    } else {
                      simpleObj[k] = v
                    }
                  }
                }
              }
              result[key] = simpleObj
            }
          }
        }
      } catch (e) {
        console.warn('[serializeProperties] error:', e)
      }
      return result
    },
    // 将一个绘制节点序列化为简易对象
    serializeNode(node) {
      if (!node) return null

      // ========== 关键修复：在序列化之前先提取文本 ==========
      let extractedText = ''

      // 方法1: 直接访问 node.text
      try {
        const directText = node.text
        if (directText !== undefined && directText !== null && String(directText).trim() !== '') {
          extractedText = String(directText)
          console.log('[serializeNode] ✓ 从 node.text 直接获取文本:', extractedText)
        }
      } catch (e) {
        console.warn('[serializeNode] 读取 node.text 失败:', e)
      }

      // 方法2: 尝试 getText() 方法
      if (!extractedText || extractedText.trim() === '') {
        try {
          if (typeof node.getText === 'function') {
            const methodText = node.getText()
            if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
              extractedText = String(methodText)
              console.log('[serializeNode] ✓ 从 getText() 获取文本:', extractedText)
            }
          }
        } catch (e) {
          console.warn('[serializeNode] getText() 调用失败:', e)
        }
      }

      // 方法3: 从 getProperties() 获取
      let props = {}
      try {
        props = typeof node.getProperties === 'function' ? node.getProperties() : {}
        if (!extractedText && props && props.text !== undefined && props.text !== null) {
          const propsText = String(props.text)
          if (propsText.trim() !== '') {
            extractedText = propsText
            console.log('[serializeNode] ✓ 从 getProperties().text 获取文本:', extractedText)
          }
        }
      } catch (e) {
        console.warn('[serializeNode] getProperties error:', e)
      }

      // 深度序列化 properties
      const serializedProps = this.serializeProperties(props)

      // 如果已经提取到文本，强制设置到 serializedProps 中
      if (extractedText && extractedText.trim() !== '') {
        serializedProps.text = extractedText
        console.log('[serializeNode] ✓ 已强制设置 serializedProps.text =', extractedText)
      }

      if (typeof node.getText === 'function' || extractedText || serializedProps.text || node.text) {
        // 使用已经提取的文本
        const text = extractedText || (serializedProps.text ? String(serializedProps.text) : '')

        if (!text || text.trim() === '') {
          console.warn('[serializeNode] ⚠️ 警告：文本节点但 text 为空！', {
            node,
            extractedText,
            serializedPropsText: serializedProps.text
          })
        }
        // 获取文本样式
        let textStyle = null
        try {
          const tstyle = typeof node.getTextStyle === 'function' ? node.getTextStyle() : null
          if (tstyle) {
            textStyle = {
              font: tstyle.getFont && typeof tstyle.getFont === 'function' ? tstyle.getFont() : (tstyle.font || tstyle.lH),
              color: tstyle.getColor && typeof tstyle.getColor === 'function' ? tstyle.getColor() : (tstyle.color || tstyle.Lx),
              size: tstyle.size || tstyle.eZ,
              alignment: tstyle.getAlignment && typeof tstyle.getAlignment === 'function' ? tstyle.getAlignment() : (tstyle.alignment || tstyle.Vf)
            }
          }
        } catch (e) {
          console.warn('[serializeNode] getTextStyle error:', e)
        }
        return {
          type: 'text',
          text,
          properties: serializedProps,
          textStyle: textStyle
        }
      }
      return { type: 'path', properties: serializedProps }
    },
    // 获取所有需要提交的标注节点（包含图层中的节点和当前工具正在编辑的节点）
    getAllAnnotationNodes() {
      const nodes = []
      try {
        const layer = this.annotations
        if (layer && typeof layer.getChildren === 'function') {
          const children = layer.getChildren() || []
          for (const n of children) nodes.push(n)
        }
        // 同时尝试从上下两个 widget 的 overlay/manipulator 层获取
        const tryPushLayerChildren = (widget) => {
          if (!widget || typeof widget.getOverlayLayer !== 'function') return
          try {
            const overlay = widget.getOverlayLayer()
            const manip = widget.getManipulatorLayer && widget.getManipulatorLayer()
            const arrs = []
            if (overlay && typeof overlay.getChildren === 'function') arrs.push(overlay.getChildren() || [])
            if (manip && typeof manip.getChildren === 'function') arrs.push(manip.getChildren() || [])
            for (const arr of arrs) {
              for (const n of arr) {
                if (nodes.indexOf(n) === -1) nodes.push(n)
              }
            }
          } catch (e) { }
        }
        tryPushLayerChildren(this._seismicWidget)
        tryPushLayerChildren(this._seismicWidgetBottom)
        // 包含当前编辑但可能尚未附加到图层的形状
        const toolNodes = []
        try { if (this.annotationTool && typeof this.annotationTool.getShape === 'function') { const s = this.annotationTool.getShape(); if (s) toolNodes.push(s) } } catch (e) { }
        try { if (this.pencilTool && typeof this.pencilTool.getShape === 'function') { const s = this.pencilTool.getShape(); if (s) toolNodes.push(s) } } catch (e) { }
        for (const s of toolNodes) {
          if (nodes.indexOf(s) === -1) nodes.push(s)
        }
      } catch (e) { }
      try {
        console.log('[collect] nodes total:', nodes.length, 'top/bottom widgets:', !!this._seismicWidget, !!this._seismicWidgetBottom)
        nodes.slice(0, 5).forEach((n, i) => {
          const hasText = typeof n.getText === 'function'
          const props = typeof n.getProperties === 'function' ? n.getProperties() : {}
          console.log(`[collect] node#${i}`, hasText ? 'text' : 'path', props)
        })
      } catch (e) { }
      return nodes
    },

    // 判断节点属于哪个面板（top/bottom）
    getNodePanel(node) {
      try {
        const inLayer = (widget) => {
          if (!widget) return false;
          const overlay = widget.getOverlayLayer && widget.getOverlayLayer();
          const manip = widget.getManipulatorLayer && widget.getManipulatorLayer();
          const has = (layer) => layer && typeof layer.indexOfChild === 'function' && layer.indexOfChild(node) >= 0;
          return has(overlay) || has(manip);
        };
        if (inLayer(this._seismicWidget)) return 'top';
        if (inLayer(this._seismicWidgetBottom)) return 'bottom';
      } catch (e) { }
      return 'top';
    },

    // 收集当前注释层（文本/线条）为简单可序列化结构
    collectAnnotationData() {
      const result = []
      try {
        // 首先尝试使用缓存的标注数据
        if (Array.isArray(this.collectedAnnotations) && this.collectedAnnotations.length > 0) {
          console.log('[collectAnnotationData] 使用缓存的标注数据，数量:', this.collectedAnnotations.length);
          // 过滤掉 _nodeRef 字段，只保留可序列化的数据
          const cachedData = this.collectedAnnotations.map(item => {
            const { _nodeRef, ...cleanItem } = item;
            return cleanItem;
          });
          return cachedData;
        }

        const nodes = this.getAllAnnotationNodes()
        if (!Array.isArray(nodes) || nodes.length === 0) {
          console.log('[collectAnnotationData] 未找到节点，返回空数组');
          return result;
        }

        for (const node of nodes) {
          if (!node) continue

          // ========== 关键修复：在序列化之前先提取文本 ==========
          // 必须先提取文本，因为序列化可能会丢失数据
          let extractedText = ''

          // 优先检查缓存中是否有该节点的文本
          const cachedItem = Array.isArray(this.collectedAnnotations)
            ? this.collectedAnnotations.find(item => item._nodeRef === node)
            : null;

          if (cachedItem && cachedItem.text && String(cachedItem.text).trim() !== '') {
            extractedText = String(cachedItem.text);
            console.log('[collectAnnotationData] ✓ 从缓存获取文本:', extractedText);
          }

          // 方法1: 直接访问 node.text（最直接的方式）
          try {
            const directText = node.text
            if (directText !== undefined && directText !== null && String(directText).trim() !== '') {
              extractedText = String(directText)
              console.log('[collectAnnotationData] ✓ 从 node.text 直接获取文本:', extractedText)
            }
          } catch (e) {
            console.warn('[collectAnnotationData] 读取 node.text 失败:', e)
          }

          // 方法2: 尝试 getText() 方法
          if (!extractedText || extractedText.trim() === '') {
            try {
              if (typeof node.getText === 'function') {
                const methodText = node.getText()
                if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
                  extractedText = String(methodText)
                  console.log('[collectAnnotationData] ✓ 从 getText() 获取文本:', extractedText)
                }
              }
            } catch (e) {
              console.warn('[collectAnnotationData] getText() 调用失败:', e)
            }
          }

          // 方法3: 从 getProperties() 获取（但要立即读取，不要等序列化）
          if (!extractedText || extractedText.trim() === '') {
            try {
              if (typeof node.getProperties === 'function') {
                const rawProps = node.getProperties()
                if (rawProps && rawProps.text !== undefined && rawProps.text !== null) {
                  const propsText = String(rawProps.text)
                  if (propsText.trim() !== '') {
                    extractedText = propsText
                    console.log('[collectAnnotationData] ✓ 从 getProperties().text 获取文本:', extractedText)
                  }
                }
              }
            } catch (e) {
              console.warn('[collectAnnotationData] getProperties() 调用失败:', e)
            }
          }

          // 现在获取 properties 进行序列化
          let props = {}
          try {
            props = typeof node.getProperties === 'function' ? node.getProperties() : {}
          } catch (e) {
            console.warn('[collectAnnotationData] getProperties error:', e)
          }

          // 深度序列化 properties
          const serializedProps = this.serializeProperties(props)

          // 如果已经提取到文本，强制设置到 serializedProps 中
          if (extractedText && extractedText.trim() !== '') {
            serializedProps.text = extractedText
            console.log('[collectAnnotationData] ✓ 已强制设置 serializedProps.text =', extractedText)
          }

          // 文本节点处理
          if (typeof node.getText === 'function' || extractedText || serializedProps.text || node.text) {
            // 使用已经提取的文本，如果为空则使用序列化后的
            const text = extractedText || (serializedProps.text ? String(serializedProps.text) : '')

            console.log('[collectAnnotationData] 最终文本提取结果:', {
              extractedText,
              serializedPropsText: serializedProps.text,
              finalText: text,
              nodeText: node.text,
              propsText: props.text
            })
            // 确保文本不为空
            if (!text || text.trim() === '') {
              console.warn('[collectAnnotationData] ⚠️ 警告：文本节点但 text 为空！', {
                node,
                extractedText,
                serializedPropsText: serializedProps.text,
                propsText: props.text
              })
            }

            // 获取文本样式
            let textStyle = null
            try {
              const tstyle = typeof node.getTextStyle === 'function' ? node.getTextStyle() : null
              if (tstyle) {
                textStyle = {
                  font: tstyle.getFont && typeof tstyle.getFont === 'function' ? tstyle.getFont() : (tstyle.font || tstyle.lH),
                  color: tstyle.getColor && typeof tstyle.getColor === 'function' ? tstyle.getColor() : (tstyle.color || tstyle.Lx),
                  size: tstyle.size || tstyle.eZ,
                  alignment: tstyle.getAlignment && typeof tstyle.getAlignment === 'function' ? tstyle.getAlignment() : (tstyle.alignment || tstyle.Vf)
                }
              }
            } catch (e) {
              console.warn('[collectAnnotationData] getTextStyle error:', e)
            }

            // 再次确保 serializedProps.text 有值
            if (text && text.trim() !== '') {
              serializedProps.text = text
            }

            result.push({
              type: 'text',
              text: text || '', // 确保至少是空字符串而不是 undefined
              properties: serializedProps,
              textStyle: textStyle,
              panel: this.getNodePanel(node)
            })
          } else {
            // 线条/路径（Paint工具创建的Path）
            result.push({
              type: 'path',
              properties: serializedProps,
              panel: this.getNodePanel(node)
            })
          }
        }
      } catch (e) {
        console.error('[collectAnnotationData] error:', e)
      }
      try {
        console.log('[collect] result length:', result.length, 'sample:', result.slice(0, 2))
        // 打印每个结果的详细信息用于调试
        result.forEach((item, index) => {
          console.log(`[collect] item#${index}:`, {
            type: item.type,
            text: item.text,
            hasText: !!item.text,
            textLength: item.text ? item.text.length : 0,
            propertiesKeys: Object.keys(item.properties || {}),
            hasTextInProps: !!item.properties?.text
          })
        })
      } catch (e) { }
      return result
    },

    // 生成批量提交数据并调用后端 addAll 接口
    async submitSegyAnnotations() {
      try {
        // xmid：优先使用路由 id，其次 zbid
        const xmid = (this.$route.params && (this.$route.params.id || this.$route.params.zbid))
          || (this.$route.query && (this.$route.query.id || this.$route.query.zbid))
          || null

        if (!xmid) {
          this.$message.warning('缺少 xmid（路由 id/zbid）')
          return
        }

        // segyid 优先使用 toDht 返回的 ysqqXmxxSegy[0].id，兜底用 segyList[0]
        let hasYsqqSegy = Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0
        let hasSegyList = Array.isArray(this.segyList) && this.segyList.length > 0
        let seg = hasYsqqSegy ? this.ysqqXmxxSegy[0] : (hasSegyList ? this.segyList[0] : null)

        if (!seg || !seg.id) {
          console.warn('[submitSegyAnnotations] no seg initially. ysqqXmxxSegy length:', (this.ysqqXmxxSegy || []).length, 'segyList length:', (this.segyList || []).length)
          // 尝试重新加载一次数据（页面初进可能尚未完成加载）
          try { await this.loadThumbData() } catch (e) { }
          hasYsqqSegy = Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0
          hasSegyList = Array.isArray(this.segyList) && this.segyList.length > 0
          seg = hasYsqqSegy ? this.ysqqXmxxSegy[0] : (hasSegyList ? this.segyList[0] : null)
          console.warn('[submitSegyAnnotations] after reload. ysqqXmxxSegy length:', (this.ysqqXmxxSegy || []).length, 'segyList length:', (this.segyList || []).length)
          if (!seg || !seg.id) {
            this.$message.warning('未找到对应的 SEGY 信息')
            return
          }
        }

        let bznr = this.collectAnnotationData()
        // 若仍为空，尝试直接抓取当前工具的 shape
        if (!Array.isArray(bznr) || bznr.length === 0) {
          try {
            const extra = []
            const s1 = this.annotationTool && typeof this.annotationTool.getShape === 'function' ? this.annotationTool.getShape() : null
            const s2 = this.pencilTool && typeof this.pencilTool.getShape === 'function' ? this.pencilTool.getShape() : null
            const n1 = this.serializeNode(s1)
            const n2 = this.serializeNode(s2)
            if (n1) extra.push(n1)
            if (n2) extra.push(n2)
            if (extra.length > 0) {
              bznr = extra
              console.log('[collect] used current tool shapes because layer/cache empty:', extra)
            }
          } catch (e) { }
        }

        // 后处理：确保所有文本项的 text 字段都被正确填充
        if (Array.isArray(bznr) && bznr.length > 0) {
          bznr = bznr.map((item, index) => {
            if (item.type === 'text') {
              console.log(`[submitSegyAnnotations] 后处理文本项 #${index}:`, {
                text: item.text,
                textType: typeof item.text,
                textLength: item.text ? item.text.length : 0,
                propertiesText: item.properties?.text,
                propertiesTextType: typeof item.properties?.text,
                propertiesKeys: Object.keys(item.properties || {})
              })

              // 如果 text 为空，尝试从 properties.text 获取
              if (!item.text || String(item.text).trim() === '') {
                if (item.properties && item.properties.text !== undefined && item.properties.text !== null) {
                  const propsText = String(item.properties.text)
                  if (propsText.trim() !== '') {
                    item.text = propsText
                    console.log(`[submitSegyAnnotations] 从 properties.text 恢复文本 #${index}:`, item.text)
                  }
                }
              }

              // 确保 text 是字符串类型且不为空
              if (item.text !== undefined && item.text !== null) {
                item.text = String(item.text)
                // 如果仍然是空字符串，记录警告
                if (item.text.trim() === '') {
                  console.warn(`[submitSegyAnnotations] 警告：文本项 #${index} 的 text 字段为空字符串！`, {
                    item,
                    properties: item.properties
                  })
                }
              } else {
                console.warn(`[submitSegyAnnotations] 警告：文本项 #${index} 的 text 字段为 undefined 或 null！`, item)
              }

              // 确保 properties.text 也有值
              if (item.text && item.text.trim() !== '') {
                if (!item.properties) {
                  item.properties = {}
                }
                item.properties.text = item.text
              }
            }
            return item
          })
        }

        // 打印准备提交的关键信息
        try {
          const counts = (Array.isArray(bznr) ? bznr.reduce((acc, it) => { acc[it.type] = (acc[it.type] || 0) + 1; return acc }, {}) : {})
          console.log('[submitSegyAnnotations] xmid:', xmid)
          console.log('[submitSegyAnnotations] segy candidate from:', hasYsqqSegy ? 'ysqqXmxxSegy[0]' : (hasSegyList ? 'segyList[0]' : 'none'))
          console.log('[submitSegyAnnotations] segyid:', seg && seg.id, 'fullSeg:', seg)
          console.log('[submitSegyAnnotations] annotations count:', counts, 'total:', Array.isArray(bznr) ? bznr.length : 0)
          console.log('[submitSegyAnnotations] annotations sample:', Array.isArray(bznr) ? bznr.slice(0, 2) : bznr)
          // 详细检查每个文本项的 text 字段
          if (Array.isArray(bznr)) {
            bznr.forEach((item, index) => {
              if (item.type === 'text') {
                console.log(`[submitSegyAnnotations] text item#${index}:`, {
                  hasText: !!item.text,
                  text: item.text,
                  textLength: item.text ? item.text.length : 0,
                  hasTextInProps: !!item.properties?.text,
                  propsText: item.properties?.text
                })
              }
            })
          }
        } catch (e) { }

        // 合并原有标注数据（从后台加载的标注）
        // 旧版（上图）的文本标注
        if (Array.isArray(this.savedAnnotations) && this.savedAnnotations.length > 0) {
          this.savedAnnotations.forEach(savedItem => {
            bznr.push({
              type: 'text',
              text: savedItem.text || '',
              properties: savedItem.properties || {},
              panel: 'top' // 旧版对应上图
            })
          })
          console.log('[submitSegyAnnotations] 合并旧版文本标注，数量:', this.savedAnnotations.length)
        }

        // 旧版（上图）的线条标注
        if (Array.isArray(this.savedLineAnnotations) && this.savedLineAnnotations.length > 0) {
          this.savedLineAnnotations.forEach(savedItem => {
            bznr.push({
              type: 'path',
              properties: savedItem.properties || {},
              panel: 'top' // 旧版对应上图
            })
          })
          console.log('[submitSegyAnnotations] 合并旧版线条标注，数量:', this.savedLineAnnotations.length)
        }

        // 新版（下图）的文本标注
        if (Array.isArray(this.savedAnnotationsBottom) && this.savedAnnotationsBottom.length > 0) {
          this.savedAnnotationsBottom.forEach(savedItem => {
            bznr.push({
              type: 'text',
              text: savedItem.text || '',
              properties: savedItem.properties || {},
              panel: 'bottom' // 新版对应下图
            })
          })
          console.log('[submitSegyAnnotations] 合并新版文本标注，数量:', this.savedAnnotationsBottom.length)
        }

        // 新版（下图）的线条标注
        if (Array.isArray(this.savedLineAnnotationsBottom) && this.savedLineAnnotationsBottom.length > 0) {
          this.savedLineAnnotationsBottom.forEach(savedItem => {
            bznr.push({
              type: 'path',
              properties: savedItem.properties || {},
              panel: 'bottom' // 新版对应下图
            })
          })
          console.log('[submitSegyAnnotations] 合并新版线条标注，数量:', this.savedLineAnnotationsBottom.length)
        }

        // 合并原有标注后，再次检查是否有可提交的数据
        if (!bznr || bznr.length === 0) {
          this.$message.warning('没有可提交的标注数据')
          return
        }

        // 将线条和文本分开处理
        const lines = [] // 线条数组
        const texts = [] // 文本数组

        bznr.forEach(item => {
          if (item.type === 'path') {
            // 线条类型
            lines.push(item)
          } else if (item.type === 'text') {
            // 文本类型
            texts.push(item)
          }
        })

        // 构建提交列表
        const list = []

        // 为每个线条创建独立的数组项
        lines.forEach(line => {
          const lx = line.panel === 'bottom' ? '新版' : '旧版';
          list.push({
            xmid: xmid,
            segyid: seg.id,
            lx: lx,
            ext1: '线条',
            bznr: JSON.stringify([line])
          })
        })

        // 为每个文本创建独立的数组项
        texts.forEach(text => {
          const lx = text.panel === 'bottom' ? '新版' : '旧版';
          list.push({
            xmid: xmid,
            segyid: seg.id,
            lx: lx,
            ext1: '文本',
            bznr: JSON.stringify([text])
          })
        })

        if (list.length === 0) {
          this.$message.warning('没有可提交的标注数据')
          return
        }

        await addAllSegyDz(list)
        this.$message.success('标注提交成功')

        // 保存成功后调用 toDht 接口
        try {
          await toDht(xmid)
          console.log('[submitSegyAnnotations] toDht 接口调用成功')
        } catch (e) {
          console.error('[submitSegyAnnotations] toDht 接口调用失败:', e)
        }
      } catch (e) {
        this.$message.error('标注提交失败')
      }
    },
    // 处理路由变化的方法
    async handleRouteChange() {
      //console.log('[index2] 处理路由变化，重新初始化组件');

      // 重置组件状态
      this.resetToInitialState();

      // 清空当前图表
      this.clearCurrentPlots();

      // 重置缩略图状态
      this.thumbReady = false;
      this.segyList = [];
      this.currentSegyIndex = 0;

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

      // 重新初始化场景
      if (this.$refs.plot) {
        this.createScene(this.$refs.plot, { autoloadDemo: false });
        // 重新绑定事件监听器
        this.$nextTick(() => {
          this.bindContextMenuListeners();
        });
      }

      // 重新加载数据
      try {
        await this.loadThumbData();
        if (Array.isArray(this.segyList) && this.segyList.length > 0) {
          await this.loadCurrentSegy();
        } else {
          // 无接口数据：若没有路由id，允许加载演示数据；若有id但无数据，保持空白
          const hasId = !!this.routeId;
          if (!hasId) {
            this.shouldLoadDemo = false;
            try {
              await this.handleFileSelect(this.plots);
            } catch (e) {
              console.warn('[index2] 加载演示数据失败:', e);
            }
          } else {
            this.clearCurrentPlots();
            console.info('[index2] 该项目无可用SEGY数据');
          }
        }
      } catch (e) {
        console.error('[index2] 重新加载数据失败:', e);
        this.loadingError = '数据加载失败，请刷新页面重试';
      }

      // 重新初始化缩略图 - 让YsgcIndex组件自己处理数据加载
      this.thumbReady = false;
      setTimeout(() => {
        this.thumbReady = true;
        // YsgcIndex组件会通过idOverride属性自动加载数据，不需要手动处理
      }, 100);
    },

    // 强制刷新缩略图
    forceRefreshThumb() {
      //console.log('[index2] 强制刷新缩略图');
      this.thumbReady = false;
      this.$nextTick(() => {
        this.thumbReady = true;
        // YsgcIndex组件会通过key值变化自动重新渲染并加载数据
      });
    },

    ensureThumbRendered() {
      try {
        const holder = this.$refs.thumbHolder;
        if (!holder) return;
        const rect = holder.getBoundingClientRect();
        if (rect.width === 0 || rect.height === 0) {
          holder.style.setProperty('width', '260px', 'important');
          holder.style.setProperty('height', '160px', 'important');
          holder.style.setProperty('display', 'block', 'important');
          holder.style.setProperty('visibility', 'visible', 'important');
        }
        // 如果子节点为空，放一个占位
        if (!holder.firstChild) {
          const test = document.createElement('div');
          test.style.cssText = 'width:260px;height:160px;background:#f2f2f2;border:1px dashed #ccc;';
          holder.appendChild(test);
        }
      } catch (e) { /* ignore */ }
    },
    drawThumbDirect() {
      try {
        const holder = this.$refs.thumbHolder;
        if (!holder) return;
        // 清空并创建容器
        holder.innerHTML = '';
        const el = document.createElement('div');
        el.style.cssText = 'width:260px;height:160px;background:#f2f2f2;';
        holder.appendChild(el);
        const chart = echarts.init(el, null, { width: 260, height: 160 });
        // 构造数据（使用已加载到 index2 的 thumbPoints/thumbLines，如无则画占位）
        const hasData = (this.thumbPoints && this.thumbPoints.length) || (this.thumbLines && this.thumbLines.length);
        const option = hasData ? this.buildThumbOption() : {
          backgroundColor: '#f2f2f2',
          grid: { top: 8, left: 8, right: 8, bottom: 8 },
          xAxis: { type: 'value', min: 0, max: 100, show: false },
          yAxis: { type: 'value', min: 0, max: 100, show: false },
          series: [
            { type: 'line', data: [[0, 0], [100, 0], [100, 100], [0, 100], [0, 0]], showSymbol: false, lineStyle: { color: '#ff7a45', width: 2 } },
            { type: 'scatter', data: [[10, 10], [50, 50], [90, 90]], symbolSize: 10, itemStyle: { color: '#ff4d4f' } }
          ],
          animation: false
        };
        chart.setOption(option, true);

        // 绑定双击事件：双击某条线，加载对应的上下SEGY（新/旧）
        try {
          // 系列下标说明：
          // buildThumbOption 会在最前面插入边框(line) => 索引0
          // 如果存在井点，会有一个散点系列 => 可能是索引1
          // 之后按顺序依次是每一条线。我们需要把 seriesIndex 映射到 segyList 的下标
          const hasPoints = Array.isArray(this.thumbPoints) && this.thumbPoints.length > 0;
          const lineSeriesBaseIndex = 1 + (hasPoints ? 1 : 0); // 边框1 + 可选散点1

          chart.off('dblclick');
          chart.on('dblclick', (params) => {
            if (params && params.seriesType === 'line') {
              const seriesIndex = params.seriesIndex;
              const lineIdx = seriesIndex - lineSeriesBaseIndex;
              if (lineIdx >= 0 && Array.isArray(this.segyList) && lineIdx < this.segyList.length) {
                const seg = this.segyList[lineIdx];
                console.log(this.segyList, 'this.segyList');
                this.currentSegyIndex = lineIdx;
                if (seg) {
                  // 加载该线对应的新/旧SEGY：jbsegy -> 顶部，xbsegy -> 底部
                  this.loadDualSegyFiles(seg.jbsegy, seg.xbsegy, seg.jbsegyName, seg.xbsegyName);
                }
              }
            }
          });
        } catch (e) { /* ignore binding errors */ }
      } catch (e) { /* ignore */ }
    },
    // 顶部操作：切换布局与上一/下一道（占位）
    setVerticalLayout() {
      this.layoutMode = 'vertical';
      this.showDualChart();
      this.$nextTick(() => this.resizeAfterLayout());
    },
    // 已移除全局浮动缩略图容器，缩略图仅在本页右上角显示
    setHorizontalLayout() {
      this.layoutMode = 'horizontal';
      this.showDualChart();
      this.$nextTick(() => this.resizeAfterLayout());
    },
    resizeAfterLayout() {

      try { this.updateBaseCanvasSize(); } catch (e) { }
      try { this._seismicWidget && this._seismicWidget.invalidate(); } catch (e) { }
      try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate(); } catch (e) { }
    },
    async handlePrevTrace() {
      //console.log('[index2] 上一道 clicked');
      // 优先使用 ysqqXmxxSegy，兜底使用 segyList
      const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
        ? this.ysqqXmxxSegy
        : this.segyList;

      if (!Array.isArray(segList) || segList.length === 0) {
        //console.log('[index2] segyList 为空，尝试重新加载');
        try {
          await this.loadThumbData();
        } catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
      }

      // 重新获取数据源（可能在loadThumbData后更新）
      const finalSegList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
        ? this.ysqqXmxxSegy
        : this.segyList;

      if (!Array.isArray(finalSegList) || finalSegList.length === 0) {
        console.warn('[index2] 没有可用的segy数据');
        return;
      }

      // 计算上一个索引
      this.currentSegyIndex = this.currentSegyIndex > 0 ? this.currentSegyIndex - 1 : finalSegList.length - 1;
      //console.log('[index2] 切换到上一道，当前索引:', this.currentSegyIndex);

      // 加载当前segy文件
      this.loadCurrentSegy();
    },
    async handleNextTrace() {
      //console.log('[index2] 下一道 clicked');
      // 优先使用 ysqqXmxxSegy，兜底使用 segyList
      const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
        ? this.ysqqXmxxSegy
        : this.segyList;

      if (!Array.isArray(segList) || segList.length === 0) {
        //console.log('[index2] segyList 为空，尝试重新加载');
        try {
          await this.loadThumbData();
        } catch (e) { console.warn('[index2] 重新加载segy失败:', e); }
      }

      // 重新获取数据源（可能在loadThumbData后更新）
      const finalSegList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
        ? this.ysqqXmxxSegy
        : this.segyList;

      if (!Array.isArray(finalSegList) || finalSegList.length === 0) {
        console.warn('[index2] 没有可用的segy数据');
        return;
      }

      // 计算下一个索引
      this.currentSegyIndex = this.currentSegyIndex < finalSegList.length - 1 ? this.currentSegyIndex + 1 : 0;
      //console.log('[index2] 切换到下一道，当前索引:', this.currentSegyIndex);

      // 加载当前segy文件
      this.loadCurrentSegy();
    },
    // 加载当前segy文件
    async loadCurrentSegy() {
      this.isLoading = true;
      // 优先使用 ysqqXmxxSegy 获取数据，兜底使用 segyList
      const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
        ? this.ysqqXmxxSegy  // 优先使用从 toDht 接口获取的原始数据
        : this.segyList;      // 兜底使用 segyList

      if (segList.length === 0) {
        //console.log('[index2] 没有segy数据可加载');
        this.isLoading = false;
        return;
      }

      const currentSegy = segList[this.currentSegyIndex];
      if (!currentSegy) {
        console.log('[index2] 当前segy数据不存在');
        this.isLoading = false;
        return;
      }

      //console.log('[index2] 加载segy文件 Top/Bottom:', (currentSegy.jbsegyName || currentSegy.jbsegy), (currentSegy.xbsegyName || currentSegy.xbsegy));
      //console.log('[index2] segy文件路径 Top/Bottom:', currentSegy.jbsegy, currentSegy.xbsegy);

      try {
        // 双图加载：jbsegy -> 顶部；xbsegy -> 底部
        // 根据后台返回的 ysqqXmxxSegy 数据，jbsegy 顶部展示，xbsegy 底部展示
        await this.loadDualSegyFiles(currentSegy.jbsegy, currentSegy.xbsegy, currentSegy.jbsegyName, currentSegy.xbsegyName);
        console.log('加载');

      } catch (error) {
        console.error('[index2] 加载segy文件失败:', error);
      } finally {
        // <-- 自动标注还原
        try {
          const originSegy = segList[this.currentSegyIndex] || segList[0];
          console.log('[loadCurrentSegy] 准备恢复标注，使用数据源:',
            Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
            'originSegy:', originSegy);
          // 顶部用 jbbznr，底部用 xbbznr
          await this.renderAnnotationsFromJbbznr(originSegy);
          await this.renderAnnotationsFromXbbznr(originSegy);
          // 统一在标注恢复后，强制刷新上下两个widget，避免非悬浮状态下显示旧帧
          // 减少刷新频率，避免底部图闪烁
          try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
          // 关键修复：切换下一道后，强制将底部 widget 绑定为当前 pipeline，并重新插入绘制工具，防止短暂显示上一道
          try {
            // 确保 pipeline/路径键为当前（只在必要时调用，避免频繁刷新）
            await this.assertBottomPipelineCurrent();
            // 移除重复的 refreshBottomDisplay 调用，避免闪烁
            // this.refreshBottomDisplay(); // 注释掉，因为 assertBottomPipelineCurrent 已经会刷新

            // 确保 plots 对象存在（如果为 null，重新创建）
            if (!this.plots && this._seismicWidget && this.$refs.plot) {
              try {
                this.plots = new Plot({
                  'canvasElement': this.$refs.plot,
                  'root': this._seismicWidget
                });
              } catch (e) {
                console.warn('[loadCurrentSegy] 重新创建 plots 失败:', e);
              }
            }

            // 重新插入顶部工具（有些环境下 setPipeline 后工具管理器会丢失已插入的工具）
            if (this._seismicWidget && this.checkWidgetStatus()) {
              // 如果工具还没有初始化，先初始化它们
              if (!this.annotationTool || !this.annotations) {
                try {
                  this.initAnnotationTools(this._seismicWidget);
                } catch (e) {
                  console.warn('[loadCurrentSegy] 初始化顶部注释工具失败:', e);
                }
              }

              const tm = this._seismicWidget.getTool && this._seismicWidget.getTool();
              if (tm) {
                // 重新插入顶部 annotationTool
                if (this.annotationTool) {
                  try { tm.remove(this.annotationTool); } catch (e) { }
                  try { tm.insert(0, this.annotationTool); } catch (e) { }
                  // 工具启用状态根据当前面板同步
                  try { this.annotationTool.setEnabled(!!this.isDrawingText); } catch (e) { }
                }
                // 重新插入顶部 pencilTool（如果已创建）
                if (this.pencilTool) {
                  try { tm.remove(this.pencilTool); } catch (e) { }
                  try { tm.insert(0, this.pencilTool); } catch (e) { }
                  // 工具启用状态根据当前面板同步
                  try { this.pencilTool.setEnabled(!!this.showLineStylePanel); } catch (e) { }
                }
              }
            }

            // 重新插入底部工具（有些环境下 setPipeline 后工具管理器会丢失已插入的工具）
            if (this._seismicWidgetBottom) {
              // 如果底部工具还没有初始化，先初始化它们
              if (!this.annotationToolBottom) {
                try {
                  this.initAnnotationToolsBottom(this._seismicWidgetBottom);
                } catch (e) {
                  console.warn('[loadCurrentSegy] 初始化底部注释工具失败:', e);
                }
              }

              const tm = this._seismicWidgetBottom.getTool && this._seismicWidgetBottom.getTool();
              if (tm) {
                // 先移除所有工具
                try { this.pencilToolBottom && tm.remove(this.pencilToolBottom); } catch (e) { }
                try { this.annotationToolBottom && tm.remove(this.annotationToolBottom); } catch (e) { }

                // 根据当前激活的工具，只插入需要的工具，并确保顺序正确
                if (this.showLineStylePanel && this.pencilToolBottom) {
                  // 线条工具激活时，只插入线条工具，确保文本工具被禁用
                  try {
                    // 暂时冻结 widget 更新，避免刷新导致闪烁
                    try {
                      if (this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
                      }
                    } catch (e) { }

                    tm.insert(0, this.pencilToolBottom);
                    this.pencilToolBottom.setMode(PaintMode.Pencil);
                    this.pencilToolBottom.setEditMode(EditMode.Create);
                    this.pencilToolBottom.setEnabled(true);

                    // 恢复 widget 更新
                    try {
                      if (this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
                      }
                    } catch (e) { }
                  } catch (e) {
                    // 确保即使出错也恢复更新
                    try {
                      if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
                      }
                    } catch (e2) { }
                  }
                  // 确保文本工具被禁用
                  if (this.annotationToolBottom) {
                    try {
                      this.annotationToolBottom.setEnabled(false);
                      this.annotationToolBottom.editNode(null);
                    } catch (e) { }
                  }
                } else if (this.isDrawingText && this.annotationToolBottom) {
                  // 文本工具激活时，只插入文本工具
                  try {
                    // 暂时冻结 widget 更新，避免刷新导致闪烁
                    try {
                      if (this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
                      }
                    } catch (e) { }

                    tm.insert(0, this.annotationToolBottom);
                    // 关键修复：设置文本工具属性，确保底部图可以输入文本
                    const fontString = `${this.textStyle.bold ? 'bold ' : ''}${this.textStyle.italic ? 'italic ' : ''}${this.textStyle.size || 22}px ${this.textStyle.font || 'Sans-serif'}`;
                    const textProperties = {
                      'editmode': EditMode.Create,
                      'mode': PaintMode.Text,
                      'node': {
                        'textstyle': new TextStyle({
                          color: this.textStyle.color || '#000000',
                          size: this.textStyle.size || 22,
                          font: fontString,
                          alignment: this.textStyle.align || 'left',
                          bold: this.textStyle.bold || false,
                          italic: this.textStyle.italic || false
                        }),
                        'textbox': {
                          'border': (this.textStyle.borderRadius || 0) > 0,
                          'borderradius': this.textStyle.borderRadius || 0,
                          'padding': (this.textStyle.borderRadius || 0) > 0 ? (this.textStyle.borderRadius || 0) : 5,
                          'fixedsize': this.textStyle.fixedFont || false
                        },
                        'selectable': true,
                        'movable': true,
                        'editable': true,
                        'preserveontextfinish': true,
                        'preserveonblur': true,
                        'autofocus': true,
                        'sizemode': this.textStyle.fixedFont ?
                          (SizeMode.FixedWidth | SizeMode.FixedHeight) :
                          SizeMode.WrappedWidth
                      }
                    };
                    this.annotationToolBottom.setProperties(textProperties);
                    this.annotationToolBottom.setEnabled(true);

                    // 恢复 widget 更新
                    try {
                      if (this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
                      }
                    } catch (e) { }
                  } catch (e) {
                    console.warn('[loadCurrentSegy] 设置底部文本工具属性失败:', e);
                    // 确保即使出错也恢复更新
                    try {
                      if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
                        this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
                      }
                    } catch (e2) { }
                  }
                  // 确保线条工具被禁用
                  if (this.pencilToolBottom) {
                    try {
                      this.pencilToolBottom.setEnabled(false);
                    } catch (e) { }
                  }
                } else {
                  // 都没有激活，都插入但都禁用
                  try { this.pencilToolBottom && tm.insert(0, this.pencilToolBottom); } catch (e) { }
                  try { this.annotationToolBottom && tm.insert(0, this.annotationToolBottom); } catch (e) { }
                  try { this.pencilToolBottom && this.pencilToolBottom.setEnabled(false); } catch (e) { }
                  try { this.annotationToolBottom && this.annotationToolBottom.setEnabled(false); } catch (e) { }
                }
              }
              // 移除这里的 invalidate，避免频繁刷新导致闪烁
              // try { this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
            }

            // 关键：确保 isWidgetReady 在加载完成后为 true
            if (this._seismicWidget && this.checkWidgetStatus()) {
              this.isWidgetReady = true;
            }
          } catch (e) {
            console.warn('[loadCurrentSegy] 重新插入工具时出错:', e);
          }
        } catch (e) {
          console.error('[index2] 标注恢复失败:', e);
        } finally {
          this.isLoading = false;
        }
      }
    },

    // 从接口返回的 xbbznr 数据中解析并恢复标注
    async renderAnnotationsFromXbbznr(originSegy) {
      try {
        console.log('[renderAnnotationsFromXbbznr] 开始执行，originSegy:', originSegy);
        console.log('[renderAnnotationsFromXbbznr] currentSegyIndex:', this.currentSegyIndex);
        console.log('[renderAnnotationsFromXbbznr] ysqqXmxxSegy:', this.ysqqXmxxSegy);
        console.log('[renderAnnotationsFromXbbznr] segyList:', this.segyList);

        if (!originSegy) {
          console.log('[renderAnnotationsFromXbbznr] originSegy 为空，跳过恢复');
          return;
        }

        let xbbznr = originSegy.xbbznr;
        console.log('[renderAnnotationsFromXbbznr] xbbznr 原始值1233333:', xbbznr);
        console.log('[renderAnnotationsFromXbbznr] xbbznr 类型333333:', typeof xbbznr);

        // 如果 xbbznr 是字符串，需要解析为对象
        if (xbbznr && typeof xbbznr === 'string') {
          try {
            xbbznr = JSON.parse(xbbznr);
            console.log('[renderAnnotationsFromXbbznr] JSON 解析成功，xbbznr:', xbbznr);
          } catch (e) {
            console.warn('[renderAnnotationsFromXbbznr] JSON 解析失败:', e);
            console.warn('[renderAnnotationsFromXbbznr] 解析失败的 xbbznr 内容:', xbbznr);
            return;
          }
        }

        console.log('[renderAnnotationsFromXbbznr] 解析后的 xbbznr:', xbbznr, '类型:', typeof xbbznr, '是否为数组:', Array.isArray(xbbznr));

        if (!xbbznr) {
          console.log('[renderAnnotationsFromXbbznr] xbbznr 为空，跳过恢复');
          return;
        }

        // xbbznr 现在应该是解析后的对象或数组
        let annotationList = [];
        // 如果已经是数组，直接使用；如果是对象，尝试转换为数组
        if (Array.isArray(xbbznr)) {
          annotationList = xbbznr;
          console.log('[renderAnnotationsFromXbbznr] xbbznr 是数组，直接使用，长度:', annotationList.length);
        } else if (typeof xbbznr === 'object' && xbbznr !== null) {
          // 如果是对象，尝试转换为数组
          annotationList = [xbbznr];
          console.log('[renderAnnotationsFromXbbznr] xbbznr 是对象，转换为数组，长度:', annotationList.length);
        } else {
          console.warn('[renderAnnotationsFromXbbznr] xbbznr 不是有效的数组或对象:', xbbznr, '类型:', typeof xbbznr);
          return;
        }

        console.log('[renderAnnotationsFromXbbznr] JSON 解析成功，annotationList:', annotationList);
        console.log('[renderAnnotationsFromXbbznr] annotationList 类型:', Array.isArray(annotationList) ? 'Array' : typeof annotationList);
        console.log('[renderAnnotationsFromXbbznr] annotationList 长度:', annotationList.length);

        if (!Array.isArray(annotationList) || annotationList.length === 0) {
          console.log('[renderAnnotationsFromXbbznr] 标注列表为空，跳过恢复', {
            isArray: Array.isArray(annotationList),
            length: annotationList ? annotationList.length : 0,
            annotationList: annotationList
          });
          return;
        }

        console.log('[renderAnnotationsFromXbbznr] 开始解析标注数据，数量:', annotationList.length);
        console.log('[renderAnnotationsFromXbbznr] annotationList 详细内容:', JSON.stringify(annotationList, null, 2));

        // 清空现有的底部 savedAnnotations 和 savedLineAnnotations
        this.savedAnnotationsBottom = [];
        this.savedLineAnnotationsBottom = [];

        // 转换数据格式并存储到对应的数组
        console.log('[renderAnnotationsFromXbbznr] 开始转换数据，annotationList 长度:', annotationList.length);
        annotationList.forEach((item, index) => {
          try {
            console.log(`[renderAnnotationsFromXbbznr] 处理第 ${index + 1} 项:`, {
              ext1: item.ext1,
              hasBznr: !!item.bznr,
              item: item
            });

            // 检查是否有 ext1 和 bznr 字段（新格式）
            if (item.ext1 && item.bznr) {
              // 新格式：根据 ext1 字段判断类型
              let bznrData = null;
              try {
                // 解析 bznr（可能是字符串或已经是数组）
                if (typeof item.bznr === 'string') {
                  bznrData = JSON.parse(item.bznr);
                } else if (Array.isArray(item.bznr)) {
                  bznrData = item.bznr;
                } else {
                  bznrData = [item.bznr];
                }
              } catch (e) {
                console.error(`[renderAnnotationsFromXbbznr] 解析 bznr 失败 #${index + 1}:`, e);
                return;
              }

              // 确保 bznrData 是数组
              if (!Array.isArray(bznrData)) {
                bznrData = [bznrData];
              }

              if (item.ext1 === '文本') {
                // 处理文本标注
                bznrData.forEach((bznrItem, bznrIndex) => {
                  if (bznrItem.type === 'text') {
                    // 提取文本内容
                    const text = bznrItem.text || bznrItem.properties?.text || '';
                    console.log(`[renderAnnotationsFromXbbznr] 提取的文本: "${text}"`);

                    // 转换 properties 格式
                    const properties = { ...bznrItem.properties };
                    console.log(`[renderAnnotationsFromXbbznr] 原始 properties:`, properties);

                    // 处理 textstyle - 转换格式
                    if (bznrItem.properties && bznrItem.properties.textstyle) {
                      properties.textstyle = bznrItem.properties.textstyle;
                    } else if (bznrItem.textStyle) {
                      properties.textstyle = {
                        Lx: bznrItem.textStyle.color || '#000000',
                        lH: bznrItem.textStyle.font || '22px Sans-serif',
                        Vf: bznrItem.textStyle.alignment || 'left',
                        eZ: bznrItem.textStyle.size || '22px'
                      };
                    } else {
                      properties.textstyle = {
                        Lx: '#000000',
                        lH: '22px Sans-serif',
                        Vf: 'left',
                        eZ: '22px'
                      };
                    }

                    properties.text = text;

                    if (!properties.linestyle) {
                      properties.linestyle = {
                        Lx: '#0351ad',
                        fA: 2
                      };
                    }

                    if (!properties.fillstyle) {
                      properties.fillstyle = {
                        Lx: '#c7e1f6'
                      };
                    }

                    const annotationData = {
                      text: text,
                      properties: properties
                    };

                    this.savedAnnotationsBottom.push(annotationData);
                    console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注 #${index + 1}-${bznrIndex + 1}:`, {
                      text: annotationData.text,
                      hasProperties: !!annotationData.properties
                    });
                  }
                });
              } else if (item.ext1 === '线条') {
                // 处理线条标注
                bznrData.forEach((bznrItem, bznrIndex) => {
                  if (bznrItem.type === 'path') {
                    const lineData = {
                      properties: bznrItem.properties || {}
                    };
                    this.savedLineAnnotationsBottom.push(lineData);
                    console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注 #${index + 1}-${bznrIndex + 1}`);
                  }
                });
              }
            } else {
              // 旧格式兼容：直接处理 item（保持向后兼容）
              if (item.type === 'text') {
                const text = item.text || item.properties?.text || '';
                const properties = { ...item.properties };

                if (item.properties && item.properties.textstyle) {
                  properties.textstyle = item.properties.textstyle;
                } else if (item.textStyle) {
                  properties.textstyle = {
                    Lx: item.textStyle.color || '#000000',
                    lH: item.textStyle.font || '22px Sans-serif',
                    Vf: item.textStyle.alignment || 'left',
                    eZ: item.textStyle.size || '22px'
                  };
                } else {
                  properties.textstyle = {
                    Lx: '#000000',
                    lH: '22px Sans-serif',
                    Vf: 'left',
                    eZ: '22px'
                  };
                }

                properties.text = text;

                if (!properties.linestyle) {
                  properties.linestyle = {
                    Lx: '#0351ad',
                    fA: 2
                  };
                }

                if (!properties.fillstyle) {
                  properties.fillstyle = {
                    Lx: '#c7e1f6'
                  };
                }

                const annotationData = {
                  text: text,
                  properties: properties
                };

                this.savedAnnotationsBottom.push(annotationData);
                console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换文本标注（旧格式） #${index + 1}`);
              } else if (item.type === 'path') {
                const lineData = {
                  properties: item.properties || {}
                };
                this.savedLineAnnotationsBottom.push(lineData);
                console.log(`[renderAnnotationsFromXbbznr] ✓ 已转换线条标注（旧格式） #${index + 1}`);
              }
            }
          } catch (error) {
            console.error(`[renderAnnotationsFromXbbznr] 转换标注 #${index + 1} 时出错:`, error);
          }
        });

        console.log('[renderAnnotationsFromXbbznr] 转换完成，bottom savedAnnotations 数量:', this.savedAnnotationsBottom.length, 'bottom savedLineAnnotations 数量:', this.savedLineAnnotationsBottom.length);
        console.log('[renderAnnotationsFromXbbznr] bottom savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotationsBottom, null, 2));
        console.log('[renderAnnotationsFromXbbznr] bottom savedLineAnnotations 完整数据:', JSON.stringify(this.savedLineAnnotationsBottom, null, 2));

        // 等待组件就绪后恢复标注
        if (this.savedAnnotationsBottom.length > 0 || this.savedLineAnnotationsBottom.length > 0) {
          // 确保底部 annotations 层已创建
          if (!this.annotationsBottom && this._seismicWidgetBottom) {
            this.annotationsBottom = new Group();
            const manip = this._seismicWidgetBottom.getManipulatorLayer && this._seismicWidgetBottom.getManipulatorLayer();
            const layer = manip || this._seismicWidgetBottom.getOverlayLayer();
            if (layer) {
              layer.addChild(this.annotationsBottom);
              this.annotationsBottom.setVisible(true);
            }
          } else if (this.annotationsBottom) {
            // 清空现有的标注节点，避免重复
            try {
              const children = this.annotationsBottom.getChildren ? this.annotationsBottom.getChildren() : [];
              children.forEach(child => {
                try {
                  if (child.dispose && typeof child.dispose === 'function') {
                    child.dispose();
                  }
                } catch (e) {
                  console.warn('[renderAnnotationsFromXbbznr] 清理节点失败:', e);
                }
              });
              this.annotationsBottom.removeAllChildren && this.annotationsBottom.removeAllChildren();
              console.log('[renderAnnotationsFromXbbznr] 已清空现有标注节点');
            } catch (e) {
              console.warn('[renderAnnotationsFromXbbznr] 清空标注层失败:', e);
            }
          }

          // 延迟恢复，确保图表已加载完成
          this.$nextTick(() => {
            setTimeout(() => {
              if (this.savedAnnotationsBottom.length > 0) {
                this.restoreAnnotationsBottom();
                console.log('[renderAnnotationsFromXbbznr] 底部文本标注恢复完成，共恢复', this.savedAnnotationsBottom.length, '个标注');
              }
              if (this.savedLineAnnotationsBottom.length > 0) {
                this.restoreLineAnnotationsBottom();
                console.log('[renderAnnotationsFromXbbznr] 底部线条标注恢复完成，共恢复', this.savedLineAnnotationsBottom.length, '个标注');
              }
            }, 500);
          });
        }
      } catch (error) {
        console.error('[renderAnnotationsFromXbbznr] 处理 xbbznr 数据时出错:', error);
      }
    },

    // 从接口返回的 jbbznr 数据中解析并恢复到顶部图
    async renderAnnotationsFromJbbznr(originSegy) {
      try {
        if (!originSegy) return;
        let jbbznr = originSegy.jbbznr;
        if (jbbznr && typeof jbbznr === 'string') {
          try { jbbznr = JSON.parse(jbbznr); } catch (e) { return; }
        }
        if (!jbbznr) return;
        const annotationList = Array.isArray(jbbznr) ? jbbznr : [jbbznr];
        this.savedAnnotations = [];
        this.savedLineAnnotations = [];
        annotationList.forEach((item) => {
          try {
            if (item.ext1 && item.bznr) {
              let bznrData = null;
              try {
                if (typeof item.bznr === 'string') bznrData = JSON.parse(item.bznr);
                else if (Array.isArray(item.bznr)) bznrData = item.bznr; else bznrData = [item.bznr];
              } catch (e) { return; }
              if (!Array.isArray(bznrData)) bznrData = [bznrData];
              if (item.ext1 === '文本') {
                bznrData.forEach((bznrItem) => {
                  if (bznrItem.type === 'text') {
                    const text = bznrItem.text || bznrItem.properties?.text || '';
                    const properties = { ...bznrItem.properties };
                    if (bznrItem.properties && bznrItem.properties.textstyle) {
                      properties.textstyle = bznrItem.properties.textstyle;
                    } else if (bznrItem.textStyle) {
                      properties.textstyle = {
                        Lx: bznrItem.textStyle.color || '#000000',
                        lH: bznrItem.textStyle.font || '22px Sans-serif',
                        Vf: bznrItem.textStyle.alignment || 'left',
                        eZ: bznrItem.textStyle.size || '22px'
                      };
                    } else {
                      properties.textstyle = { Lx: '#000000', lH: '22px Sans-serif', Vf: 'left', eZ: '22px' };
                    }
                    properties.text = text;
                    if (!properties.linestyle) properties.linestyle = { Lx: '#0351ad', fA: 2 };
                    if (!properties.fillstyle) properties.fillstyle = { Lx: '#c7e1f6' };
                    this.savedAnnotations.push({ text, properties });
                  }
                });
              } else if (item.ext1 === '线条') {
                bznrData.forEach((bznrItem) => {
                  if (bznrItem.type === 'path') this.savedLineAnnotations.push({ properties: bznrItem.properties || {} });
                });
              }
            } else {
              if (item.type === 'text') {
                const text = item.text || item.properties?.text || '';
                const properties = { ...item.properties };
                if (item.properties && item.properties.textstyle) properties.textstyle = item.properties.textstyle; else if (item.textStyle) {
                  properties.textstyle = { Lx: item.textStyle.color || '#000000', lH: item.textStyle.font || '22px Sans-serif', Vf: item.textStyle.alignment || 'left', eZ: item.textStyle.size || '22px' };
                } else { properties.textstyle = { Lx: '#000000', lH: '22px Sans-serif', Vf: 'left', eZ: '22px' }; }
                properties.text = text;
                if (!properties.linestyle) properties.linestyle = { Lx: '#0351ad', fA: 2 };
                if (!properties.fillstyle) properties.fillstyle = { Lx: '#c7e1f6' };
                this.savedAnnotations.push({ text, properties });
              } else if (item.type === 'path') {
                this.savedLineAnnotations.push({ properties: item.properties || {} });
              }
            }
          } catch (e) { }
        });
        if (this.savedAnnotations.length > 0 || this.savedLineAnnotations.length > 0) {
          if (!this.annotations && this._seismicWidget) {
            this.annotations = new Group();
            const manip = this._seismicWidget.getManipulatorLayer && this._seismicWidget.getManipulatorLayer();
            const layer = manip || this._seismicWidget.getOverlayLayer();
            if (layer) { layer.addChild(this.annotations); this.annotations.setVisible(true); }
          } else if (this.annotations) {
            // 清空现有顶部标注，避免重复
            try {
              // const children = this.annotations.getChildren ? this.annotations.getChildren() : [];
              // children.forEach(child => { try { child.dispose && child.dispose(); } catch (e) { } });
              // this.annotations.removeAllChildren && this.annotations.removeAllChildren();
            } catch (e) { }
          }
          const doRestore = () => {
            if (this.savedAnnotations.length > 0) this.restoreAnnotations();
            if (this.savedLineAnnotations.length > 0) this.restoreLineAnnotations();
          };
          this.$nextTick(() => {
            setTimeout(() => {
              if (!this._seismicWidget) {
                setTimeout(doRestore, 400);
              } else {
                doRestore();
              }
            }, 500);
          });
        }
      } catch (e) { console.error('[renderAnnotationsFromJbbznr] 处理 jbbznr 数据时出错:', e); }
    },
    // 清空当前图表
    clearCurrentPlots() {
      //console.log('[index2] 清空当前图表');
      try {
        // 重置鼠标悬浮状态，避免切换时显示错误的图
        this.isHovering = false;

        // 清空主图表并强制刷新
        if (this._seismicWidget) {
          try {
            // 检查 clear 方法是否存在，如果存在则调用
            if (typeof this._seismicWidget.clear === 'function') {
              this._seismicWidget.clear();
            }
            // 如果没有 clear 方法，跳过清空操作，后续设置新 pipeline 会覆盖旧数据
          } catch (e) {
            console.warn('清空顶部widget时出错:', e);
          }
          // 强制刷新以确保旧数据被清除
          try {
            if (this._seismicWidget.invalidate) {
              this._seismicWidget.invalidate();
            }
          } catch (e) {
            console.warn('刷新顶部widget时出错:', e);
          }
        }
        // 清空底部图表并强制刷新
        if (this._seismicWidgetBottom) {
          try {
            // 检查 clear 方法是否存在，如果存在则调用
            if (typeof this._seismicWidgetBottom.clear === 'function') {
              this._seismicWidgetBottom.clear();
            }
            // 如果没有 clear 方法，跳过清空操作，后续设置新 pipeline 会覆盖旧数据
          } catch (e) {
            console.warn('清空底部widget时出错:', e);
          }
          // 强制刷新以确保旧数据被清除
          try {
            if (this._seismicWidgetBottom.invalidate) {
              this._seismicWidgetBottom.invalidate();
            }
          } catch (e) {
            console.warn('刷新底部widget时出错:', e);
          }
        }
        // 清空plots数据
        this.plots = null;
        this.plotsBottom = null;
      } catch (e) {
        console.warn('[index2] 清空图表时出错:', e);
      }
    },
    // 加载segy文件的具体实现
    async loadSegyFile(segyPath) {
      //console.log('[index2] 开始加载segy文件:', segyPath);

      try {
        // 只显示主图表，隐藏底部图表
        this.showSingleChart();

        // 重新创建主图表场景
        if (this.$refs.plot) {
          // 清空现有场景
          this.clearScene(this.$refs.plot);
          // 重新创建场景
          this.createScene(this.$refs.plot);
          // 重新绑定事件监听器
          this.$nextTick(() => {
            this.bindContextMenuListeners();
          });
        }

        //console.log('[index2] segy文件加载完成');

      } catch (error) {
        console.error('[index2] 加载segy文件时出错:', error);
        throw error;
      }
    },
    // 同时加载上下两个segy（jbsegy到顶部，xbsegy到底部）
    async loadDualSegyFiles(jbPath, xbPath, jbName, xbName) {
      // 兜底：若无路径，则给出提示
      if (!jbPath && !xbPath) {
        console.warn('[index2] 无可加载的SEGY文件');
        return;
      }

      // 重置鼠标悬浮状态，避免切换时显示错误的图
      this.isHovering = false;

      // 打开双图布局
      this.showDualChart();

      // 不再隐藏容器，避免首次绘制依赖鼠标事件触发
      const topScroll = this.$refs.topScroll;
      const bottomScroll = this.$refs.bottomScroll;

      // 清空现有图表
      this.clearCurrentPlots();

      // 清空 pipeline 引用，确保旧数据被清除
      this.pipeline = null;
      this.pipelineBottom = null;
      this.plots = null;
      this.plotsBottom = null;

      // 确保两个画布已初始化（如果widget不存在，才创建新的）
      if (this.$refs.plot && !this._seismicWidget) {
        this.createScene(this.$refs.plot, { autoloadDemo: false });
      }
      if (this.$refs.plot2 && !this._seismicWidgetBottom) {
        this.initSecondWidget(this.$refs.plot2);
      }
      // 重新绑定事件监听器
      this.$nextTick(() => {
        this.bindContextMenuListeners();
      });

      // 等待一小段时间，确保清空操作完成
      await new Promise(resolve => setTimeout(resolve, 50));

      // 顺序加载，分别统计成功与失败，但不立即刷新
      let topOk = false;
      let bottomOk = false;
      try {
        if (jbPath) {
          const topTitle = jbName || this.extractFileName(jbPath) || 'jbsegy';
          await this.loadSegyIntoWidget('top', jbPath, topTitle, false); // 不立即刷新
          topOk = true;
        }
      } catch (e) {
        console.warn('加载上部SEGY失败:', e);
      }

      try {
        if (xbPath) {
          const bottomTitle = xbName || this.extractFileName(xbPath) || 'xbsegy';
          await this.loadSegyIntoWidget('bottom', xbPath, bottomTitle, false); // 不立即刷新
          bottomOk = true;
        }
      } catch (e) {
        console.warn('加载下部SEGY失败:', e);
      }

      // 等待所有数据加载完成后再统一刷新
      if (topOk || bottomOk) {
        // 使用 requestAnimationFrame 确保在下一帧统一刷新
        await this.$nextTick();
        requestAnimationFrame(() => {
          try {
            if (topOk && this._seismicWidget) {
              if (this._seismicWidget.invalidate) {
                this._seismicWidget.invalidate();
              }
              this.setScrollbarCSS(this._seismicWidget);
              this.forceDisableInternalScrollbars();
              setTimeout(() => {
                try {
                  if (this._seismicWidget && this._seismicWidget.fitToBounds) {
                    this._seismicWidget.fitToBounds();
                  }
                } catch (e) { }
              }, 100);
            }
            if (bottomOk && this._seismicWidgetBottom) {
              if (this._seismicWidgetBottom.invalidate) {
                this._seismicWidgetBottom.invalidate();
              }
              this.setScrollbarCSS(this._seismicWidgetBottom);
              this.forceDisableInternalScrollbars();
              setTimeout(() => {
                try {
                  if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) {
                    this._seismicWidgetBottom.fitToBounds();
                  }
                  // 额外在显示前进行一次尺寸同步与重绘
                  try { this.updateBaseCanvasSize(); } catch (e) { }
                  try { this.plotsBottom && typeof this.plotsBottom.redraw === 'function' && this.plotsBottom.redraw(); } catch (e) { }
                } catch (e) { }
              }, 100);
            }
          } catch (e) {
            console.warn('最终刷新widget时出错:', e);
          }
        });

        // 刷新完成后，额外进行一次尺寸同步与重绘，确保无悬浮也正确
        setTimeout(() => {
          try { this.updateBaseCanvasSize(); } catch (e) { }
          try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
          try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
          requestAnimationFrame(() => {
            try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
            try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
          });
        }, 200);
      } else {
        // 加载失败也做一次重绘尝试
        try { this._seismicWidget && this._seismicWidget.invalidate && this._seismicWidget.invalidate(); } catch (e) { }
        try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
      }
    },
    // 将指定segy加载到顶部/底部widget
    // skipRefresh: 如果为 true，则不立即刷新，等待统一刷新
    async loadSegyIntoWidget(position, segyPath, displayName, skipRefresh = false) {
      // 构造可访问的完整URL
      const url = this.buildSegyURL(segyPath);

      // 拉取二进制
      //console.log('[index2] 即将拉取SEGY', { position, name: displayName, rawPath: segyPath, builtUrl: url });
      const blob = await this.fetchSegyBlob(url);
      //console.log('[index2] 已获取SEGY二进制', { position, name: displayName, size: blob && blob.size, type: blob && blob.type });
      const fileName = (displayName || this.extractFileName(segyPath) || 'data.segy');
      const filesObj = new File([blob], fileName, { type: blob.type || 'application/octet-stream', lastModified: Date.now() });
      const file = new LocalFile(filesObj);

      const segyReader = new SegyReader(file);
      await new Promise((resolve, reject) => {
        segyReader.loadMetaData((reader) => {
          if (reader instanceof Error) return reject(reader);
          resolve();
        });
      });

      const reader = segyReader;
      const statistics = await new Promise((resolve, reject) => {
        reader.readDataSetStatistics((r, stats) => {
          if (!stats) return reject(new Error('无法获取数据集统计信息'));
          resolve(stats);
        });
      });

      // 准备颜色映射
      if (!this._colorMap) {
        this.colorProvider = this.colorProvider || SeismicColors.getDefault();
        this.registerColorMaps(this.colorProvider);
        this._colorMap = this.colorProvider.createNamedColorMap('WhiteBlack', 256);
      }

      const pipeline = new SeismicPipeline(fileName, reader, statistics)
        .setColorMap(this._colorMap)
        .setOptions({
          'normalization': { 'type': NormalizationType.RMS, 'scale': 0.4 },
          'plot': { 'type': { 'Wiggle': false, 'InterpolatedDensity': true }, 'decimationSpacing': 5 },
          'colors': { 'colorMap': this._colorMap }
        });

      try { pipeline.addTraceProcessor(new TaperFilterProcess({ 'apply': false, 'name': 'TaperFilter' })); } catch (e) { }
      try { pipeline.addTraceProcessor(new AGC({ 'apply': false, 'name': 'AGC' })); } catch (e) { }
      try { pipeline.addTraceProcessor(new Reverse({ 'apply': false, 'name': 'Reverse' })); } catch (e) { }

      if (position === 'top') {
        // 先清空旧的 pipeline 数据，避免显示错误的图片
        // 无论是否有旧的 pipeline，都要清空，确保切换下一道时显示新图
        if (this._seismicWidget) {
          try {
            // 先移除旧的 pipeline（如果存在）
            if (this.pipeline && this._seismicWidget.setPipeline) {
              // 尝试移除旧的 pipeline，先设置为 undefined 或空对象来触发清空
              try {
                // 如果 widget 有 removePipeline 方法，使用它
                if (typeof this._seismicWidget.removePipeline === 'function') {
                  this._seismicWidget.removePipeline();
                }
              } catch (e) {
                // 如果 removePipeline 不存在，忽略错误
              }
            }
            // 检查 clear 方法是否存在，如果存在则调用
            if (typeof this._seismicWidget.clear === 'function') {
              this._seismicWidget.clear();
            }
            // 强制刷新以确保旧数据被清除
            if (this._seismicWidget.invalidate) {
              this._seismicWidget.invalidate();
            }
          } catch (e) {
            console.warn('清空顶部widget数据时出错:', e);
          }
        }

        // 清空旧的 pipeline 引用
        this.pipeline = null;
        this.plots = null;

        if (!this._seismicWidget && this.$refs.plot) {
          this.createScene(this.$refs.plot);
          // 重新绑定事件监听器
          this.$nextTick(() => {
            this.bindContextMenuListeners();
          });
        }
        if (!this._seismicWidget) throw new Error('顶部Widget未初始化');

        // 设置新的 pipeline
        this.pipeline = pipeline;
        this._seismicWidget.setPipeline(pipeline);
        this._seismicWidget.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': displayName || this.extractFileName(segyPath) || pipeline.getName() } } } });

        // 关键修复：恢复 plots 对象，确保工具栏功能可用
        if (!this.plots && this._seismicWidget && this.$refs.plot) {
          try {
            this.plots = new Plot({
              'canvasElement': this.$refs.plot,
              'root': this._seismicWidget
            });
          } catch (e) {
            console.warn('[loadSegyIntoWidget] 恢复 plots 失败:', e);
          }
        }

        // 如果不跳过刷新，则立即刷新；否则等待统一刷新
        if (!skipRefresh) {
          // 强制刷新以确保显示新的数据
          this.$nextTick(() => {
            try {
              if (this._seismicWidget.invalidate) {
                this._seismicWidget.invalidate();
              }
            } catch (e) { }
          });

          setTimeout(() => { try { this._seismicWidget.fitToBounds(); } catch (e) { } }, 200);
        }
        this.setScrollbarCSS(this._seismicWidget);
        this.forceDisableInternalScrollbars();
      } else {
        // 先清空旧的 pipeline 数据，避免显示错误的图片
        // 无论是否有旧的 pipeline，都要清空，确保切换下一道时显示新图
        if (this._seismicWidgetBottom) {
          try {
            // 先移除旧的 pipeline（如果存在）
            if (this.pipelineBottom && this._seismicWidgetBottom.setPipeline) {
              // 尝试移除旧的 pipeline，先设置为 undefined 或空对象来触发清空
              try {
                // 如果 widget 有 removePipeline 方法，使用它
                if (typeof this._seismicWidgetBottom.removePipeline === 'function') {
                  this._seismicWidgetBottom.removePipeline();
                }
              } catch (e) {
                // 如果 removePipeline 不存在，忽略错误
              }
            }
            // 检查 clear 方法是否存在，如果存在则调用
            if (typeof this._seismicWidgetBottom.clear === 'function') {
              this._seismicWidgetBottom.clear();
            }
            // 强制刷新以确保旧数据被清除
            if (this._seismicWidgetBottom.invalidate) {
              this._seismicWidgetBottom.invalidate();
            }
          } catch (e) {
            console.warn('清空底部widget数据时出错:', e);
          }
        }

        // 清空旧的 pipeline 引用
        this.pipelineBottom = null;
        this.plotsBottom = null;

        if (!this._seismicWidgetBottom && this.$refs.plot2) this.initSecondWidget(this.$refs.plot2);
        if (!this._seismicWidgetBottom) throw new Error('底部Widget未初始化');

        // 设置新的 pipeline，并记录为"当前版本"
        this.pipelineBottom = pipeline;
        const newKey = displayName || this.extractFileName(segyPath) || pipeline.getName();
        const newPath = segyPath;

        // 关键修复：如果 pipeline、路径和名称都没有变化，不需要重新设置，避免不必要的刷新
        if (this._seismicWidgetBottom.getPipeline && this._seismicWidgetBottom.getPipeline() === pipeline &&
          String(this._bottomSegyPath) === String(newPath) && String(this._bottomSegyKey) === String(newKey)) {
          // 完全一致，不需要做任何操作
          return;
        }

        this._bottomSegyKey = newKey;
        this._bottomSegyPath = newPath;

        // 关键修复：在设置 pipeline 前冻结更新，避免中间状态刷新
        let wasFrozen = false;
        try {
          if (this._seismicWidgetBottom.setOptions) {
            wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
          }
        } catch (e) { }

        this._seismicWidgetBottom.setPipeline(pipeline);
        this._seismicWidgetBottom.setOptions({ 'axes': { 'samples': { 'title': { 'visible': true, 'text': newKey } } } });

        // 恢复更新（如果 skipRefresh 为 false，会在后面刷新）
        try {
          if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined && skipRefresh) {
            // 如果 skipRefresh 为 true，先恢复更新，但不立即刷新
            this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
          }
        } catch (e) { }

        // 如果不跳过刷新，则立即刷新；否则等待统一刷新
        if (!skipRefresh) {
          // 恢复更新（如果之前被冻结）
          try {
            if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
          } catch (e) { }

          // 强制刷新以确保显示新的数据
          this.$nextTick(() => {
            try {
              if (this._seismicWidgetBottom.invalidate) {
                this._seismicWidgetBottom.invalidate();
              }
              // 在下一帧再次刷新，避免首次绘制未完成造成的残影
              requestAnimationFrame(() => {
                try { this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate(); } catch (e) { }
                // 如果 plotsBottom 支持 redraw，额外触发一次重绘
                try { this.plotsBottom && typeof this.plotsBottom.redraw === 'function' && this.plotsBottom.redraw(); } catch (e) { }
              });
            } catch (e) { }
          });

          setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
        }
        this.setScrollbarCSS(this._seismicWidgetBottom);
        this.forceDisableInternalScrollbars();
      }
    },
    // 根据后端网关构造SEGY访问URL
    buildSegyURL(path) {
      if (!path) return '';
      // 如果已经是完整URL，直接返回
      if (/^https?:\/\//i.test(path)) return path;
      // 否则拼接VUE_APP_BASE_API
      const base = (process.env.VUE_APP_BASE_API || '').replace(/\/$/, '');
      const p = (path || '').startsWith('/') ? path : `/${path}`;
      // RuoYi 上传资源通常通过下载转发接口访问
      if (p.startsWith('/profile/')) {
        return `${base}/common/download/resource?resource=${encodeURIComponent(p)}`;
      }
      return `${base}${p}`;
    },
    // 提取路径中的文件名
    extractFileName(p) {
      try {
        if (!p) return '';
        const clean = String(p).split('?')[0];
        return clean.split('/').pop() || '';
      } catch (e) { return ''; }
    },
    // 拉取SEGY二进制
    async fetchSegyBlob(url) {
      if (!url) throw new Error('无效的SEGY地址');
      const token = getToken();
      const base = (process.env.VUE_APP_BASE_API || '').replace(/\/$/, '');
      const headers = { Authorization: 'Bearer ' + token };

      // 构造候选URL列表：优先使用传入的url，然后尝试直接资源路径等
      const attempts = [];
      attempts.push({ url, headers });

      const dlMatch = url.match(/\/(common\/download\/resource)\?resource=([^&]+)/);
      if (dlMatch) {
        const resourceEnc = dlMatch[2];
        const resource = decodeURIComponent(resourceEnc);
        // 直接用 base + resource
        if (base && resource) attempts.push({ url: `${base}${resource}`, headers });
        // 仅用资源相对路径
        if (resource) attempts.push({ url: resource, headers });
      }

      // 同一批URL再尝试无鉴权头（有些静态资源是公开的）
      const more = attempts.map(a => ({ url: a.url }));
      attempts.push(...more);

      // 针对编码resource的404，再试未编码版本
      const encodedMatch = url.match(/resource=([^&]+)/);
      if (encodedMatch) {
        const rawUrl = url.replace(/resource=([^&]+)/, (m, v) => `resource=${decodeURIComponent(v)}`);
        attempts.unshift({ url: rawUrl, headers });
        attempts.push({ url: rawUrl });
      }
      const errors = [];
      for (const attempt of attempts) {
        try {
          //console.log('[index2] fetchSegyBlob 尝试', { url: attempt.url, withAuth: !!attempt.headers });
          const res = await fetch(attempt.url, attempt.headers ? { headers: attempt.headers } : {});
          if (!res.ok) {
            const text = await res.text().catch(() => '');
            errors.push(`${attempt.url} -> ${res.status} ${res.statusText}${text ? ' - ' + text.slice(0, 120) : ''}`);
            continue;
          }
          const contentType = (res.headers && res.headers.get && res.headers.get('content-type')) || '';
          const blob = await res.blob();
          // 拦截返回HTML或可疑体积的情况，避免GeoToolkit解析报错
          if (/(text\/html|application\/json)/i.test(contentType)) {
            const text = await res.text().catch(() => '');
            errors.push(`${attempt.url} -> 非SEGY(HTML/JSON)，内容: ${text.slice(0, 120)}`);
            continue;
          }
          if (blob && blob.size > 0) return blob;
          errors.push(`${attempt.url} -> 空文件(size=0)`);
        } catch (e) {
          errors.push(`${attempt.url} -> 异常: ${e && e.message ? e.message : e}`);
        }
      }

      throw new Error('获取到的文件数据为空；尝试的URL：\n' + errors.join('\n'));
    },
    // 显示单个图表（隐藏底部图表）
    showSingleChart() {
      //console.log('[index2] 切换到单图表显示模式');

      // 隐藏底部图表容器
      const bottomScroll = this.$refs.bottomScroll;
      if (bottomScroll) {
        bottomScroll.style.display = 'none';
      }

      // 调整顶部图表容器，使其占满整个可视区域
      const topScroll = this.$refs.topScroll;
      if (topScroll) {
        topScroll.style.height = '100%';
        topScroll.style.flex = '1';
      }

      // 更新布局模式
      this.layoutMode = 'single';
    },
    // 显示双图表（恢复上下或左右布局）
    showDualChart() {
      //console.log('[index2] 切换到双图表显示模式');

      // 显示底部图表容器
      const bottomScroll = this.$refs.bottomScroll;
      if (bottomScroll) {
        bottomScroll.style.display = '';
      }

      // 调整顶部图表容器高度
      const topScroll = this.$refs.topScroll;
      if (topScroll) {
        topScroll.style.height = '';
        topScroll.style.flex = '';
      }

      // 重新创建底部图表
      if (this.$refs.plot2) {
        this.initSecondWidget(this.$refs.plot2);
      }
    },
    // 清空场景
    clearScene(container) {
      if (!container) return;

      try {
        // 清空容器内容
        container.innerHTML = '';

        // 重置相关变量
        this.plots = null;
        this._seismicWidget = null;

        //console.log('[index2] 场景已清空');
      } catch (e) {
        console.warn('[index2] 清空场景时出错:', e);
      }
    },
    handleThumbClick() {
      // 如果正在拖动或拖动距离超过阈值，不触发点击事件
      if (this.isDragging || this.dragDistance > this.dragThreshold) {
        return;
      }
      this.showThumbDialog = true;
    },
    // 开始拖动
    startDrag(event) {
      // 只有点击拖动指示器或缩略图边缘才开始拖动
      if (!event.target.closest('.drag-handle') && !event.target.closest('.thumb-holder')) {
        return;
      }

      event.preventDefault();
      this.isDragging = false; // 初始状态不是拖动
      this.dragDistance = 0;
      this.dragStartX = event.clientX;
      this.dragStartY = event.clientY;

      // 添加全局事件监听
      document.addEventListener('mousemove', this.onDrag);
      document.addEventListener('mouseup', this.stopDrag);
    },
    // 拖动中
    onDrag(event) {
      event.preventDefault();

      const deltaX = event.clientX - this.dragStartX;
      const deltaY = event.clientY - this.dragStartY;
      this.dragDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);

      // 只有拖动距离超过阈值才开始真正的拖动
      if (this.dragDistance > this.dragThreshold) {
        if (!this.isDragging) {
          this.isDragging = true;
          // 添加拖动样式
          if (this.$refs.thumbContainer) {
            this.$refs.thumbContainer.style.cursor = 'grabbing';
          }
        }

        // 获取当前缩略图的位置
        const currentTop = parseInt(this.thumbPosition.top) || 150;
        const currentRight = parseInt(this.thumbPosition.right) || 20;

        // 计算新位置
        let newTop = currentTop + deltaY;
        let newRight = currentRight - deltaX;

        // 边界检查
        const windowWidth = window.innerWidth;
        const windowHeight = window.innerHeight;
        const thumbWidth = 260;
        const thumbHeight = 160;

        // 限制在窗口范围内
        newTop = Math.max(0, Math.min(newTop, windowHeight - thumbHeight));
        newRight = Math.max(0, Math.min(newRight, windowWidth - thumbWidth));

        // 更新位置
        this.thumbPosition = {
          top: newTop + 'px',
          right: newRight + 'px',
          left: 'auto',
          bottom: 'auto'
        };

        // 更新起始位置
        this.dragStartX = event.clientX;
        this.dragStartY = event.clientY;
      }
    },
    // 停止拖动
    stopDrag() {
      // 移除全局事件监听
      document.removeEventListener('mousemove', this.onDrag);
      document.removeEventListener('mouseup', this.stopDrag);

      // 恢复样式
      if (this.$refs.thumbContainer) {
        this.$refs.thumbContainer.style.cursor = 'grab';
      }

      // 延迟重置拖动状态，避免立即触发点击事件
      setTimeout(() => {
        this.isDragging = false;
        this.dragDistance = 0;
      }, 100);
    },
    // 处理缩略图（绿色线）点击/双击事件
    async onThumbLinePick(payload) {
      try {
        if (!payload) return;

        console.log('[index2] onThumbLinePick 收到事件:', payload);
        console.log('[index2] segyList 长度:', this.segyList ? this.segyList.length : 0);
        console.log('[index2] segyList 前3项:', this.segyList ? this.segyList.slice(0, 3).map((s, i) => ({ index: i, id: s && s.id, name: s && (s.name || s.segyName || s.jbsegyName || s.xbsegyName) })) : []);

        // 优先通过 ID 匹配，如果没有 ID 则通过索引匹配
        let lineIdx = -1;
        if (payload.id != null) {
          // 通过 ID 查找在 segyList 中的索引
          lineIdx = this.segyList.findIndex(seg => seg && seg.id == payload.id);
          console.log('[index2] 通过 ID 查找结果:', { id: payload.id, lineIdx });
        }

        // 如果通过 ID 没找到，则使用原始索引（originalIndex）
        if (lineIdx === -1 && payload.originalIndex != null) {
          lineIdx = payload.originalIndex;
          console.log('[index2] 使用 originalIndex:', { originalIndex: payload.originalIndex, lineIdx });
        }

        // 如果还是没有找到，使用过滤后的索引作为兜底（兼容旧逻辑）
        if (lineIdx === -1 && typeof payload.index === 'number') {
          lineIdx = payload.index;
          console.log('[index2] 使用过滤后的 index:', { index: payload.index, lineIdx });
        }

        if (lineIdx === -1 || !Array.isArray(this.segyList) || lineIdx < 0 || lineIdx >= this.segyList.length) {
          console.warn('[index2] onThumbLinePick: 无法找到对应的线条', {
            payload,
            lineIdx,
            segyListLength: this.segyList ? this.segyList.length : 0
          });
          return;
        }

        const seg = this.segyList[lineIdx];
        console.log('[index2] 设置 currentSegyIndex:', { lineIdx, segId: seg && seg.id, segName: seg && (seg.name || seg.segyName || seg.jbsegyName || seg.xbsegyName) });
        this.currentSegyIndex = lineIdx;

        // 立即关闭弹窗，给用户反馈
        if (this.showThumbDialog) {
          this.showThumbDialog = false;
        }

        // 设置加载状态，避免显示错误的图
        if (seg) {
          this.isLoading = true;
          try {
            // 等待数据加载完成
            await this.loadDualSegyFiles(seg.jbsegy, seg.xbsegy, seg.jbsegyName, seg.xbsegyName);
          } catch (error) {
            console.error('[index2] loadDualSegyFiles 加载失败:', error);
          } finally {
            // 数据加载完成后关闭加载状态
            this.isLoading = false;
          }
        }
      } catch (e) {
        console.error('[index2] onThumbLinePick error:', e);
        // 确保出错时也关闭加载状态
        this.isLoading = false;
      }
    },
    // 确保缩略图渲染
    ensureThumbRendered() {
      if (!this.thumbReady) {
        this.thumbReady = true;
      }
    },
    // ====== 缩略图（ECharts） ======
    async initThumb() {
      // 已弃用：现在缩略图直接嵌入 YsgcIndex
      return;
    },
    // 测试缩略图方法
    testThumb() {
      //console.log('[index2] ===== testThumb START =====');

      // 创建完全独立的测试容器
      let testContainer = document.getElementById('thumb-test-container');
      if (testContainer) {
        testContainer.remove();
      }

      testContainer = document.createElement('div');
      testContainer.id = 'thumb-test-container';
      testContainer.style.position = 'fixed';
      testContainer.style.top = '20px';
      testContainer.style.right = '20px';
      testContainer.style.width = '260px';
      testContainer.style.height = '160px';
      testContainer.style.backgroundColor = '#e3f2fd';
      testContainer.style.border = '2px solid #2196f3';
      testContainer.style.display = 'flex';
      testContainer.style.alignItems = 'center';
      testContainer.style.justifyContent = 'center';
      testContainer.style.fontSize = '16px';
      testContainer.style.color = '#1976d2';
      testContainer.style.zIndex = '9999';
      testContainer.style.boxShadow = '0 4px 8px rgba(0,0,0,0.2)';
      testContainer.style.borderRadius = '4px';
      testContainer.textContent = '测试缩略图 - 独立容器';

      document.body.appendChild(testContainer);

      //console.log('[index2] testThumb: independent container created');
      //console.log('[index2] testContainer size:', testContainer.clientWidth, 'x', testContainer.clientHeight);
      //console.log('[index2] ===== testThumb END =====');
    },
    // 测试ECharts方法
    testECharts() {
      //console.log('[index2] ===== testECharts START =====');

      // 清理现有容器
      let chartContainer = document.getElementById('thumb-chart-container');
      if (chartContainer) {
        chartContainer.remove();
      }

      // 创建新的ECharts容器
      chartContainer = document.createElement('div');
      chartContainer.id = 'thumb-chart-container';
      // 先添加到DOM，再设置样式
      document.body.appendChild(chartContainer);

      // 强制设置样式 - 使用setAttribute确保样式生效
      chartContainer.setAttribute('style', `
              position: fixed !important;
              top: 20px !important;
              right: 20px !important;
              width: 260px !important;
              height: 160px !important;
              background-color: #ff0000 !important;
              border: 5px solid #00ff00 !important;
              border-radius: 4px !important;
              box-shadow: 0 4px 8px rgba(0,0,0,0.5) !important;
              z-index: 99999 !important;
              opacity: 1 !important;
              visibility: visible !important;
              display: block !important;
          `);

      // 验证样式是否应用
      //console.log('[index2] Chart container style after setAttribute:', chartContainer.style.position);

      // 创建ECharts实例
      if (this.thumbChart) {
        try { this.thumbChart.dispose(); } catch (e) { }
      }

      this.thumbChart = echarts.init(chartContainer, null, {
        width: 260,
        height: 160
      });

      // 设置简单的测试数据
      const testOption = {
        title: {
          text: 'ECharts测试',
          left: 'center',
          textStyle: { fontSize: 14 }
        },
        grid: { top: 30, left: 20, right: 20, bottom: 20 },
        xAxis: {
          type: 'category',
          data: ['A', 'B', 'C', 'D', 'E'],
          axisLabel: { fontSize: 10 }
        },
        yAxis: {
          type: 'value',
          axisLabel: { fontSize: 10 }
        },
        series: [{
          type: 'line',
          data: [20, 40, 30, 50, 35],
          smooth: true,
          lineStyle: { color: '#2d72ff', width: 2 },
          itemStyle: { color: '#2d72ff' }
        }, {
          type: 'scatter',
          data: [[0, 20], [1, 40], [2, 30], [3, 50], [4, 35]],
          symbolSize: 6,
          itemStyle: { color: '#ff6b6b' }
        }],
        tooltip: { show: true },
        animation: true
      };

      this.thumbChart.setOption(testOption, true);
      //console.log('[index2] ECharts test chart created');
      //console.log('[index2] ===== testECharts END =====');
    },
    // 测试按钮点击
    testButtonClick() {
      //console.log('[index2] ===== testButtonClick START =====');
      alert('按钮点击测试成功！');
      //console.log('[index2] ===== testButtonClick END =====');
    },

    // 创建超级明显的缩略图测试
    createSuperVisibleThumb() {
      //console.log('[index2] ===== createSuperVisibleThumb START =====');

      // 清理现有容器
      let container = document.getElementById('super-visible-thumb');
      if (container) {
        container.remove();
      }

      // 创建新容器
      container = document.createElement('div');
      container.id = 'super-visible-thumb';

      // 添加到body
      document.body.appendChild(container);

      // 设置超级明显的样式
      container.style.cssText = `
              position: fixed !important;
              top: 50px !important;
              left: 50px !important;
              width: 300px !important;
              height: 200px !important;
              background-color: #ff0000 !important;
              border: 10px solid #00ff00 !important;
              border-radius: 10px !important;
              z-index: 999999 !important;
              display: flex !important;
              align-items: center !important;
              justify-content: center !important;
              font-size: 24px !important;
              color: white !important;
              font-weight: bold !important;
              text-align: center !important;
              box-shadow: 0 0 20px rgba(255,0,0,0.8) !important;
          `;

      // 添加文字内容
      container.innerHTML = `
              <div>
                  <div>🎯 缩略图测试</div>
                  <div style="font-size: 16px; margin-top: 10px;">如果你能看到这个红色框，说明容器创建成功！</div>
              </div>
          `;

      //console.log('[index2] Super visible container created');
      //console.log('[index2] Container position:', container.getBoundingClientRect());

      // 1秒后创建ECharts
      setTimeout(() => {
        //console.log('[index2] Starting ECharts creation...');

        // 清理文字，准备ECharts
        container.innerHTML = '';
        container.style.cssText = `
                  position: fixed !important;
                  top: 50px !important;
                  left: 50px !important;
                  width: 300px !important;
                  height: 200px !important;
                  background-color: #0000ff !important;
                  border: 10px solid #ffff00 !important;
                  border-radius: 10px !important;
                  z-index: 999999 !important;
                  box-shadow: 0 0 20px rgba(0,0,255,0.8) !important;
              `;

        //console.log('[index2] Container cleared and styled for ECharts');
        //console.log('[index2] Container position after styling:', container.getBoundingClientRect());

        // 创建ECharts
        if (this.thumbChart) {
          try {
            this.thumbChart.dispose();
            //console.log('[index2] Previous chart disposed');
          } catch (e) {
            //console.log('[index2] Error disposing previous chart:', e);
          }
        }

        try {
          this.thumbChart = echarts.init(container, null, {
            width: 300,
            height: 200
          });
          //console.log('[index2] ECharts instance created:', this.thumbChart);
        } catch (e) {
          console.error('[index2] Error creating ECharts instance:', e);
          return;
        }

        // 设置测试数据
        const option = {
          title: {
            text: 'ECharts 缩略图',
            left: 'center',
            textStyle: { fontSize: 16, color: '#ffffff' }
          },
          grid: { top: 40, left: 20, right: 20, bottom: 20 },
          xAxis: {
            type: 'category',
            data: ['A', 'B', 'C', 'D', 'E'],
            axisLabel: { fontSize: 12, color: '#ffffff' }
          },
          yAxis: {
            type: 'value',
            axisLabel: { fontSize: 12, color: '#ffffff' }
          },
          series: [{
            type: 'line',
            data: [20, 40, 30, 50, 35],
            smooth: true,
            lineStyle: { color: '#ffffff', width: 3 },
            itemStyle: { color: '#ffffff' }
          }, {
            type: 'scatter',
            data: [[0, 20], [1, 40], [2, 30], [3, 50], [4, 35]],
            symbolSize: 10,
            itemStyle: { color: '#ffff00' }
          }],
          tooltip: { show: true },
          animation: true
        };

        try {
          this.thumbChart.setOption(option, true);
          //console.log('[index2] ECharts option set successfully');

          // 强制渲染
          setTimeout(() => {
            if (this.thumbChart) {
              this.thumbChart.resize();
              //console.log('[index2] ECharts resized');
            }
          }, 100);

        } catch (e) {
          console.error('[index2] Error setting ECharts option:', e);
        }

        //console.log('[index2] ECharts creation completed');

      }, 1000);

      //console.log('[index2] ===== createSuperVisibleThumb END =====');
    },
    // 重置缩略图方法
    resetThumb() {
      //console.log('[index2] ===== resetThumb START =====');

      // 清理独立容器
      const testContainer = document.getElementById('thumb-test-container');
      if (testContainer) {
        testContainer.remove();
        //console.log('[index2] test container removed');
      }

      const chartContainer = document.getElementById('thumb-chart-container');
      if (chartContainer) {
        chartContainer.remove();
        //console.log('[index2] chart container removed');
      }

      const superVisibleContainer = document.getElementById('super-visible-thumb');
      if (superVisibleContainer) {
        superVisibleContainer.remove();
        //console.log('[index2] super visible container removed');
      }

      // 清理ECharts实例
      if (this.thumbChart) {
        try {
          this.thumbChart.dispose();
          this.thumbChart = null;
          //console.log('[index2] ECharts instance disposed');
        } catch (e) {
          console.warn('[index2] Error disposing ECharts:', e);
        }
      }

      // 重置原始容器
      const holder = this.$refs.thumbHolder;
      if (holder) {
        holder.innerHTML = '';
        holder.className = 'thumb-holder';
        //console.log('[index2] original container reset');
      }

      //console.log('[index2] resetThumb: all containers cleaned up');
      //console.log('[index2] ===== resetThumb END =====');
    },
    // 备用缩略图初始化方法
    async initThumbFallback() {
      //console.log('[index2] ===== initThumbFallback START =====');
      try {
        // 创建完全独立的ECharts容器
        let chartContainer = document.getElementById('thumb-chart-container');
        if (chartContainer) {
          chartContainer.remove();
        }

        chartContainer = document.createElement('div');
        chartContainer.id = 'thumb-chart-container';

        // 先添加到DOM，再设置样式
        document.body.appendChild(chartContainer);

        // 强制设置样式 - 使用setAttribute确保样式生效
        chartContainer.setAttribute('style', `
                  position: fixed !important;
                  top: 20px !important;
                  right: 20px !important;
                  width: 260px !important;
                  height: 160px !important;
                  background-color: #ffff00 !important;
                  border: 5px solid #ff00ff !important;
                  border-radius: 4px !important;
                  box-shadow: 0 4px 8px rgba(0,0,0,0.5) !important;
                  z-index: 99999 !important;
                  opacity: 1 !important;
                  visibility: visible !important;
                  display: block !important;
              `);

        // 验证样式是否应用
        //console.log('[index2] Test chart container style after setAttribute:', chartContainer.style.position);

        // 创建ECharts实例
        if (this.thumbChart) {
          try { this.thumbChart.dispose(); } catch (e) { }
        }

        this.thumbChart = echarts.init(chartContainer, null, {
          width: 260,
          height: 160
        });

        // 先显示一个简单的测试图表
        const simpleOption = {
          title: {
            text: '缩略图',
            left: 'center',
            textStyle: { fontSize: 12 }
          },
          grid: { top: 30, left: 20, right: 20, bottom: 20 },
          xAxis: {
            type: 'value',
            min: 0,
            max: 100,
            axisLabel: { show: false },
            axisTick: { show: false },
            axisLine: { show: false },
            splitLine: { show: false }
          },
          yAxis: {
            type: 'value',
            min: 0,
            max: 100,
            axisLabel: { show: false },
            axisTick: { show: false },
            axisLine: { show: false },
            splitLine: { show: false }
          },
          series: [{
            type: 'scatter',
            data: [[20, 30], [40, 50], [60, 70], [80, 20]],
            symbolSize: 8,
            itemStyle: { color: '#2d72ff' }
          }, {
            type: 'line',
            data: [[10, 20], [30, 40], [50, 60], [70, 30], [90, 50]],
            showSymbol: false,
            lineStyle: { color: '#00aa66', width: 2 }
          }],
          tooltip: { show: false },
          animation: false
        };

        this.thumbChart.setOption(simpleOption, true);
        //console.log('[index2] Simple chart displayed');

        // 检查容器状态
        //console.log('[index2] Chart container position:', chartContainer.getBoundingClientRect());
        //console.log('[index2] Chart container style:', {
        //   position: chartContainer.style.position,
        //   top: chartContainer.style.top,
        //   right: chartContainer.style.right,
        //   width: chartContainer.style.width,
        //   height: chartContainer.style.height,
        //   zIndex: chartContainer.style.zIndex,
        //   display: chartContainer.style.display,
        //   visibility: chartContainer.style.visibility
        // });

        // 然后加载真实数据
        await this.loadThumbData();
        //console.log('[index2] Data loaded, rendering real chart...');
        this.renderThumb();

        //console.log('[index2] Fallback chart initialized successfully in independent container');

      } catch (e) {
        console.error('[index2] initThumbFallback failed:', e);
      }
      //console.log('[index2] ===== initThumbFallback END =====');
    },
    async loadThumbData() {
      try {
        // 与 index.vue 相同的取数方式：优先从路由取 id
        const route = this.$route || {};
        const params = route.params || {};
        const query = route.query || {};
        const id = params.zbid || query.zbid || params.id || query.id;
        this.thumbId = id || null;
        //console.log('[index2] loadThumbData id:', id);

        // 如果没有id，使用测试数据
        if (!id) {
          //console.log('[index2] No id found, using test data for thumbnail');
          this.thumbPoints = [
            { name: '测试点1', x: 10, y: 20 },
            { name: '测试点2', x: 30, y: 40 },
            { name: '测试点3', x: 50, y: 60 }
          ];
          this.thumbLines = [
            [[10, 20], [30, 40], [50, 60]]
          ];
          this.thumbBounds = { xMin: 0, xMax: 100, yMin: 0, yMax: 100 };
          return;
        }
        const res = await toDht(id);
        const data = (res && (res.data !== undefined ? res.data : res)) || {};
        //console.log('[index2] loadThumbData res:', data);
        //console.log('[index2] data keys:', Object.keys(data));

        // 井点
        const list = Array.isArray(data.ysqqXmxxJxxList) ? data.ysqqXmxxJxxList : [];
        //console.log('[index2] jxxList length:', list.length);
        //console.log('[index2] jxxList sample:', list.slice(0, 2));

        this.thumbPoints = list
          .filter(it => it && it.x != null && it.y != null)
          .map(it => ({ name: String(it.jh || ''), x: Number(it.x), y: Number(it.y) }));
        //console.log('[index2] thumbPoints:', this.thumbPoints.length);
        //console.log('[index2] thumbPoints sample:', this.thumbPoints.slice(0, 2));
        // 线（SEGY）
        // 兼容两种返回结构：
        // 1) { ysqqXmxxSegy: [...] }
        // 2) 顶层直接返回数组 [...]
        const segys = Array.isArray(data.ysqqXmxxSegy)
          ? data.ysqqXmxxSegy
          : (Array.isArray(data) ? data : []);
        if (!Array.isArray(data.ysqqXmxxSegy) && Array.isArray(data)) {
          //console.log('[index2] ysqqXmxxSegy not found, using top-level array as segy list');
        }
        // 存储完整的segy数据列表
        this.segyList = segys;
        this.ysqqXmxxSegy = segys; // 同步保留原始数组，供提交时取 [0].id
        this.currentSegyIndex = 0; // 重置为第一个
        //console.log('[index2] segyList length:', this.segyList.length);
        //console.log('[index2] segyList sample:', this.segyList.slice(0, 2));

        this.thumbLines = segys.map(seg => {
          try {
            const arr = typeof seg.x === 'string' ? JSON.parse(seg.x) : (Array.isArray(seg.x) ? seg.x : []);
            const enriched = arr
              .filter(p => p && p.x != null && p.y != null)
              .map(p => ({ sxh: Number(p.sxh), x: Number(p.x), y: Number(p.y) }))
              .filter(p => Number.isFinite(p.x) && Number.isFinite(p.y));
            const hasSxh = enriched.every(p => Number.isFinite(p.sxh));
            const ordered = hasSxh ? enriched.sort((a, b) => a.sxh - b.sxh) : enriched;
            return ordered.map(p => [p.x, p.y]);
          } catch (e) { return []; }
        }).filter(line => line.length > 0);
        //console.log('[index2] thumbLines:', this.thumbLines.length);
        // 边界
        const xs = [];
        const ys = [];
        this.thumbPoints.forEach(p => { xs.push(p.x); ys.push(p.y); });
        this.thumbLines.forEach(line => line.forEach(([x, y]) => { xs.push(x); ys.push(y); }));
        const xMin = xs.length ? Math.min(...xs) : null;
        const xMax = xs.length ? Math.max(...xs) : null;
        const yMin = ys.length ? Math.min(...ys) : null;
        const yMax = ys.length ? Math.max(...ys) : null;
        this.thumbBounds = { xMin, xMax, yMin, yMax };
        //console.log('[index2] thumbBounds:', this.thumbBounds);

        // 如果没有数据，添加测试数据来验证图表显示
        if (this.thumbPoints.length === 0 && this.thumbLines.length === 0) {
          //console.log('[index2] 没有数据，添加测试数据');
          this.thumbPoints = [
            { name: '测试井1', x: 100, y: 200 },
            { name: '测试井2', x: 200, y: 300 },
            { name: '测试井3', x: 300, y: 150 }
          ];
          this.thumbLines = [
            [[100, 200], [150, 250], [200, 300], [250, 280], [300, 150]]
          ];
          this.thumbBounds = { xMin: 100, xMax: 300, yMin: 150, yMax: 300 };
          //console.log('[index2] 测试数据添加完成:', this.thumbPoints.length, 'points,', this.thumbLines.length, 'lines');
        }
      } catch (e) {
        console.warn('[index2] loadThumbData failed:', e);
      }
    },
    buildThumbOption() {
      const series = [];
      if (this.thumbPoints && this.thumbPoints.length) {
        series.push({
          type: 'scatter',
          symbolSize: 10,
          data: this.thumbPoints.map(p => [p.x, p.y]),
          itemStyle: { color: '#ff4d4f' },
          label: { show: false }
        });
      }
      for (const line of this.thumbLines) {
        series.push({
          type: 'line',
          data: line,
          showSymbol: false,
          lineStyle: { color: '#1677ff', width: 2 }
        });
      }

      const { xMin, xMax, yMin, yMax } = this.thumbBounds || {};

      // 如果没有数据，使用默认范围
      const defaultRange = { xMin: 0, xMax: 100, yMin: 0, yMax: 100 };
      const range = {
        xMin: xMin !== null && xMin !== undefined ? xMin : defaultRange.xMin,
        xMax: xMax !== null && xMax !== undefined ? xMax : defaultRange.xMax,
        yMin: yMin !== null && yMin !== undefined ? yMin : defaultRange.yMin,
        yMax: yMax !== null && yMax !== undefined ? yMax : defaultRange.yMax
      };

      //console.log('[index2] buildThumbOption range:', range);
      //console.log('[index2] buildThumbOption series count:', series.length);

      // 将数据归一化到 0~100 区间，保证在小图中清晰
      const dx = Math.max(1e-9, range.xMax - range.xMin);
      const dy = Math.max(1e-9, range.yMax - range.yMin);
      const norm = (pt) => [
        ((pt[0] - range.xMin) / dx) * 100,
        ((pt[1] - range.yMin) / dy) * 100
      ];
      const normalizedSeries = series.map(s => {
        if (Array.isArray(s.data) && s.data.length) {
          const data = s.data.map(norm);
          return Object.assign({}, s, { data });
        }
        return s;
      });

      // 边界辅助线，增强可见性（使用归一化后的边界）
      const border = [
        [0, 0], [100, 0], [100, 100], [0, 100], [0, 0]
      ];
      normalizedSeries.unshift({
        type: 'line',
        data: border,
        showSymbol: false,
        lineStyle: { color: '#ff7a45', width: 1, type: 'dashed' },
        silent: true,
        z: 0
      });

      return {
        backgroundColor: '#f2f2f2',
        grid: { top: 8, left: 8, right: 8, bottom: 8, containLabel: false },
        xAxis: {
          type: 'value',
          min: 0,
          max: 100,
          scale: true,
          axisLabel: { show: false },
          axisTick: { show: false },
          axisLine: { show: false },
          splitLine: { show: false }
        },
        yAxis: {
          type: 'value',
          min: 0,
          max: 100,
          inverse: false,
          scale: true,
          axisLabel: { show: false },
          axisTick: { show: false },
          axisLine: { show: false },
          splitLine: { show: false }
        },
        series: normalizedSeries,
        tooltip: { show: false },
        animation: false, // 禁用动画，确保立即显示
        graphic: [{
          type: 'text',
          left: 'center',
          top: 'middle',
          style: {
            text: '缩略图',
            fill: 'rgba(0,0,0,0.25)',
            font: 'bold 18px sans-serif'
          },
          silent: true,
          z: -1
        }]
      };
    },
    renderThumb() {
      if (!this.thumbChart) {
        console.warn('[index2] renderThumb: no chart instance');
        return;
      }
      //console.log('[index2] renderThumb: points', this.thumbPoints.length, 'lines', this.thumbLines.length);

      try {
        const option = this.buildThumbOption();
        //console.log('[index2] renderThumb option:', option);
        this.thumbChart.setOption(option, true);

        // 强制重新渲染
        setTimeout(() => {
          if (this.thumbChart) {
            this.thumbChart.resize();
            //console.log('[index2] renderThumb: chart resized after render');
          }
        }, 100);
      } catch (e) {
        console.error('[index2] renderThumb failed:', e);
      }
    },
    // 更新基准宽高，基于外层容器实际尺寸
    updateBaseCanvasSize() {
      try {
        const topEl = this.$refs.topScroll;
        if (topEl) {
          const rect = topEl.getBoundingClientRect();
          if (rect.width > 0) this.baseCanvasWidth = rect.width;
          if (rect.height > 0) this.baseCanvasHeight = rect.height;

          // 强制设置初始状态，确保不显示滚动条
          if (this._isInitialLoad) {
            //console.log('强制设置初始尺寸，不显示滚动条:', {
            //   width: this.baseCanvasWidth,
            //   height: this.baseCanvasHeight
            // });
          }
        }
      } catch (e) { /* ignore */ }
    },

    // 根据 GeoToolkit 模型范围动态计算滚动区域尺寸
    updateScrollAreaSize() {
      try {
        if (!this._seismicWidget) return;

        // 获取当前视图范围
        const currentLimits = this._seismicWidget.getModelLimits();
        if (!currentLimits) return;

        // 获取容器实际尺寸作为基准
        const topEl = this.$refs.topScroll;
        if (topEl) {
          const rect = topEl.getBoundingClientRect();
          const containerWidth = rect.width;
          const containerHeight = rect.height;

          // 获取当前视图的宽度和高度
          const viewWidth = currentLimits.getWidth();
          const viewHeight = currentLimits.getHeight();

          // 检查是否是初始状态（视图范围接近容器尺寸）
          const isInitialState = Math.abs(viewWidth - containerWidth) < 200 &&
            Math.abs(viewHeight - containerHeight) < 200;

          // 如果是初始状态，保持原始尺寸，不显示滚动条
          if (isInitialState || this._isInitialLoad) {
            this.baseCanvasWidth = containerWidth;
            this.baseCanvasHeight = containerHeight;
            //console.log('初始状态，保持容器尺寸:', {
            //   containerSize: { width: containerWidth, height: containerHeight },
            //   viewSize: { width: viewWidth, height: viewHeight },
            //   isInitialLoad: this._isInitialLoad
            // });
            return;
          }

          // 只有在用户主动缩放时才计算滚动区域
          // 使用更保守的缩放因子
          const minScale = 1.2; // 降低最小缩放比例
          const maxScale = 5;   // 降低最大缩放比例

          // 基于视图范围计算缩放比例，但只在明显缩放时才应用
          const scaleX = Math.min(maxScale, Math.max(minScale, containerWidth / viewWidth));
          const scaleY = Math.min(maxScale, Math.max(minScale, containerHeight / viewHeight));

          // 只有当缩放比例明显大于1时才更新滚动区域
          if (scaleX > 1.1 || scaleY > 1.1) {
            const scrollWidth = containerWidth * scaleX;
            const scrollHeight = containerHeight * scaleY;

            this.baseCanvasWidth = scrollWidth;
            this.baseCanvasHeight = scrollHeight;

            //console.log('用户缩放后更新滚动区域尺寸:', {
            // containerSize: { width: containerWidth, height: containerHeight },
            // currentLimits: {
            //   width: viewWidth,
            //   height: viewHeight,
            //   left: currentLimits.getLeft(),
            //   right: currentLimits.getRight(),
            //   top: currentLimits.getTop(),
            //   bottom: currentLimits.getBottom()
            // },
            //   scaleX, scaleY,
            //   newScrollWidth: scrollWidth,
            //   newScrollHeight: scrollHeight
            // });
          }
        }
      } catch (e) {
        console.warn('更新滚动区域尺寸失败:', e);
      }
    },

    // 彻底禁用滚动条工具
    disableScrollbarTools() {
      try {
        // 等待widget创建完成后再禁用
        setTimeout(() => {
          if (this._seismicWidget) {
            this.disableWidgetScrollbar(this._seismicWidget);
          }
          if (this._seismicWidgetBottom) {
            this.disableWidgetScrollbar(this._seismicWidgetBottom);
          }
        }, 100);
      } catch (e) {
        console.warn('禁用滚动条工具失败:', e);
      }
    },
    // 禁用单个widget的滚动条
    disableWidgetScrollbar(widget) {
      try {
        if (!widget) return;

        // 方法1: 禁用滚动交互
        if (widget.setScrollEnabled) {
          widget.setScrollEnabled(false);
          //console.log('已禁用widget滚动交互');
        }

        // 方法2: 禁用所有鼠标交互
        if (widget.setMouseInteractionsEnabled) {
          widget.setMouseInteractionsEnabled(false);
          //console.log('已禁用widget鼠标交互');
        }

        // 尝试其他可能的交互禁用方法
        if (widget.setInteractionsEnabled) {
          widget.setInteractionsEnabled(false);
          //console.log('已禁用widget交互');
        }

        if (widget.setWheelEnabled) {
          widget.setWheelEnabled(false);
          //console.log('已禁用widget滚轮交互');
        }

        if (widget.setPanEnabled) {
          widget.setPanEnabled(false);
          //console.log('已禁用widget平移交互');
        }

        // 方法3: 通过setOptions禁用
        widget.setOptions({
          'tools': {
            'scrollbar': {
              'enabled': false,
              'visible': false,
              'active': false
            }
          }
        });

        // 方法4: 通过工具管理器移除滚动条工具
        const toolManager = widget.getTool && widget.getTool();
        if (toolManager) {
          // 禁用现有的滚动条工具
          if (toolManager.getScrollbarTool) {
            const scrollbarTool = toolManager.getScrollbarTool();
            if (scrollbarTool) {
              try { scrollbarTool.setEnabled(false); } catch (e) { }
              try { scrollbarTool.setVisible && scrollbarTool.setVisible(false); } catch (e) { }
              try { scrollbarTool.setActive && scrollbarTool.setActive(false); } catch (e) { }
            }
          }

          // 移除所有滚动条工具
          try {
            const tools = toolManager.getTools && toolManager.getTools();
            if (tools) {
              tools.forEach(tool => {
                if (tool && tool.getType && tool.getType() === 'scrollbar') {
                  toolManager.remove(tool);
                }
              });
            }
          } catch (e) {
            // ignore
          }
        }

        // 方法5: 通过CSS隐藏滚动条
        this.setScrollbarCSS(widget);

        // 方法6: 直接操作DOM元素
        this.forceHideScrollbarDOM(widget);

      } catch (e) {
        console.warn('禁用widget滚动条失败:', e);
      }
    },

    // 强制隐藏滚动条DOM元素
    forceHideScrollbarDOM(widget) {
      try {
        if (!widget || !widget.getCanvas) return;

        const canvas = widget.getCanvas();
        if (!canvas) return;

        // 获取canvas的父容器
        const container = canvas.parentElement;
        if (!container) return;

        // 递归查找并隐藏地震图相关的滚动条元素
        const hideScrollbarElements = (element) => {
          if (!element || !element.children) return;

          Array.from(element.children).forEach(child => {
            // 跳过左侧菜单相关的元素
            if (child.closest && (child.closest('.el-menu') || child.closest('.sidebar') || child.closest('.nav-menu'))) {
              return;
            }

            const classList = Array.from(child.classList || []);
            const isScrollbar = classList.some(cls =>
              cls.toLowerCase().includes('scrollbar') ||
              cls.toLowerCase().includes('scroll') ||
              cls.includes('geotoolkit.controls.tools.scroll')
            );

            if (isScrollbar) {
              child.style.display = 'none';
              child.style.visibility = 'hidden';
              child.style.opacity = '0';
              child.style.width = '0';
              child.style.height = '0';
              child.style.position = 'absolute';
              child.style.left = '-9999px';
              child.style.top = '-9999px';
              child.style.pointerEvents = 'none';
            }

            // 递归处理子元素
            hideScrollbarElements(child);
          });
        };

        // 从容器开始查找
        hideScrollbarElements(container);

        // 只隐藏地震图相关的滚动条，不影响左侧菜单
        const seismicScrollbars = document.querySelectorAll('.gt-seismic [class*="scrollbar"], .gt-seismic [class*="Scrollbar"], .gt-seismic [class*="scroll"], .gt-seismic [class*="Scroll"], .sync-section [class*="scrollbar"], .sync-section [class*="Scrollbar"], .sync-section [class*="scroll"], .sync-section [class*="Scroll"], [class*="geotoolkit.controls.tools.scroll"]');
        seismicScrollbars.forEach(sb => {
          // 确保不隐藏左侧菜单相关的元素
          if (!sb.closest('.el-menu') && !sb.closest('.sidebar') && !sb.closest('.nav-menu')) {
            sb.style.display = 'none';
            sb.style.visibility = 'hidden';
            sb.style.opacity = '0';
            sb.style.width = '0';
            sb.style.height = '0';
            sb.style.position = 'absolute';
            sb.style.left = '-9999px';
            sb.style.top = '-9999px';
            sb.style.pointerEvents = 'none';
          }
        });

      } catch (e) {
        console.warn('强制隐藏滚动条DOM失败:', e);
      }
    },

    // 强制重置到初始状态，不显示滚动条
    resetToInitialState() {
      try {
        const topEl = this.$refs.topScroll;
        if (topEl) {
          const rect = topEl.getBoundingClientRect();
          this.baseCanvasWidth = rect.width;
          this.baseCanvasHeight = rect.height;
          this._isInitialLoad = true;

          //console.log('强制重置到初始状态:', {
          //   width: this.baseCanvasWidth,
          //   height: this.baseCanvasHeight
          // });
        }
      } catch (e) {
        console.warn('重置初始状态失败:', e);
      }
    },

    // 创建下半屏镜像视图
    initSecondWidget(canvas) {
      try {
        this.plotsBottom = new Plot({
          'canvasElement': canvas,
          'root': this._seismicWidgetBottom = new SeismicWidget(null, {
            'layouttype': 'inside',
            'tools': {
              'crosshair': { 'enabled': true }
            },
            'colorbar': {
              'axis': { 'size': 20, 'autolabelrotation': true, 'tickgenerator': { 'edge': { 'tickvisible': false, 'labelvisible': false } } },
              'title': { 'size': 0 },
              'colorbox': { 'size': 10 },
              'visible': true,
              'location': ColorBarLocation.West,
              'maxheight': '80%',
              'alignment': BoxLayoutAlignment.Center,
              'width': 60
            },
            'statusbar': {
              'visible': true,
              'location': 'bottom',
              'alignment': 'left',
              'size': 25,
              'sections': { 'time': { 'visible': true, 'width': '100px' }, 'trace': { 'visible': true, 'width': '120px' }, 'value': { 'visible': true, 'width': '120px' } },
              'info': (widget, x, y, sample) => {
                if (!sample) return { 'time': '', 'trace': '', 'value': '' };
                const autoFormat = new AutoNumberFormat(4);
                const time = sample.location && sample.location.y != null ? autoFormat.format(Math.round(sample.location.y * 100) / 100.0) : '';
                const traceNumber = sample.traceNumber != null ? (sample.traceNumber + 1).toString() : '';
                const value = sample.sampleValue != null ? sample.sampleValue.toFixed(3) : '';
                return { 'time': `Time: ${time}`, 'trace': `Trace: ${traceNumber}`, 'value': `Value: ${value}` };
              }
            },
            'axes': {
              'samples': { 'title': { 'visible': false }, 'visible': true, 'labelformat': '%.0f', 'labelvisible': true, 'tickgenerator': { 'edge': { 'tickvisible': true, 'labelvisible': true } } },
              'headers': { 'fields': [], 'options': { 'minimumSpan': 100 } }
            }
          })
        });

        // 如果已经有当前有效的 bottom pipeline，优先使用它，避免回退到旧数据
        if (this.pipelineBottom) {
          try {
            // 关键修复：检查 pipeline 是否已经设置，避免重复设置导致刷新
            const currentPipeline = this._seismicWidgetBottom.getPipeline && this._seismicWidgetBottom.getPipeline();
            if (currentPipeline !== this.pipelineBottom) {
              // 只有 pipeline 不同时才设置，并使用 freezeupdate 避免闪烁
              let wasFrozen = false;
              try {
                if (this._seismicWidgetBottom.setOptions) {
                  wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
                }
              } catch (e) { }

              this._seismicWidgetBottom.setPipeline(this.pipelineBottom);
              this._seismicWidgetBottom.setOptions({
                'axes': { 'headers': { 'fields': this._headers }, 'samples': { 'title': { 'visible': true, 'text': this.pipelineBottom.getName && this.pipelineBottom.getName() } } }
              });

              // 恢复更新
              try {
                if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
                  this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
                }
              } catch (e) { }
            }

            setTimeout(() => { try { this._seismicWidgetBottom.fitToBounds(); } catch (e) { } }, 200);
            this.setScrollbarCSS(this._seismicWidgetBottom);
            try { this.initAnnotationToolsBottom(this._seismicWidgetBottom); } catch (e) { }
            return;
          } catch (e) { /* 如果失败，再走旧流程 */ }
        }

        if (this._dataReader && this._dataStatistics && this._fileName && this._colorMap) {
          try {
            const pipelineBottom = new SeismicPipeline(this._fileName, this._dataReader, this._dataStatistics)
              .setColorMap(this._colorMap)
              .setOptions({
                'normalization': { 'type': NormalizationType.RMS, 'scale': 0.4 },
                'plot': { 'type': { 'Wiggle': false, 'InterpolatedDensity': true }, 'decimationSpacing': 5 },
                'colors': { 'colorMap': this._colorMap }
              });

            try { pipelineBottom.addTraceProcessor(new TaperFilterProcess({ 'apply': false, 'name': 'TaperFilter' })); } catch (e) { }
            try { pipelineBottom.addTraceProcessor(new AGC({ 'apply': false, 'name': 'AGC' })); } catch (e) { }
            try { pipelineBottom.addTraceProcessor(new Reverse({ 'apply': false, 'name': 'Reverse' })); } catch (e) { }

            this.pipelineBottom = pipelineBottom;

            // 关键修复：使用 freezeupdate 避免设置 pipeline 时的闪烁
            let wasFrozen = false;
            try {
              if (this._seismicWidgetBottom.setOptions) {
                wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }

            this._seismicWidgetBottom.setPipeline(pipelineBottom);
            this._seismicWidgetBottom.setOptions({
              'axes': {
                'headers': { 'fields': this._headers },
                'samples': {
                  'title': { 'visible': true, 'text': pipelineBottom.getName() }
                }
              }
            });

            // 恢复更新
            try {
              if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
              }
            } catch (e) { }
            // 延迟调用fitToBounds，确保初始状态稳定
            setTimeout(() => {
              this._seismicWidgetBottom.fitToBounds();
            }, 800);
            // 使用CSS方法彻底禁用下半屏内部滚动条
            this.setScrollbarCSS(this._seismicWidgetBottom);
            // 初始化底部注释工具
            try { this.initAnnotationToolsBottom(this._seismicWidgetBottom); } catch (e) { console.warn('初始化底部注释工具失败:', e); }
          } catch (e) {
            console.warn('初始化下半屏流水线失败:', e);
          }
        }
      } catch (error) {
        console.error('创建下半屏视图失败:', error);
      }
    },

    // 为底部 widget 初始化注释工具（文本/线条）与标注层
    initAnnotationToolsBottom(widget) {
      if (!widget) return;
      try {
        // 创建标注层
        this.annotationsBottom = new Group();
        const overlay = widget.getOverlayLayer();
        if (overlay) overlay.addChild(this.annotationsBottom);

        // 文本工具（底部）
        this.annotationToolBottom = new Paint({
          'layer': widget.getManipulatorLayer(),
          'node': {
            'radius': 10,
            'fillstyle': new FillStyle('#c7e1f6'),
            'linestyle': new LineStyle({ 'color': '#0351ad', 'width': 2 }),
            'textbox': { 'border': true, 'borderradius': 10, 'fixedsize': false, 'wordwrap': true, 'padding': 5 },
            'selectable': true,
            'movable': true,
            'editable': true,
            'preserveontextfinish': true,
            'preserveonblur': true
          }
        });

        // 选择工具（限制在底部标注层）
        const selectionToolBottom = new Selection()
          .setNodeFilter((nodes) => nodes.filter((node) => this.annotationsBottom.indexOfChild(node) >= 0))
          .addListener(SelectionEvents.onPick, (tool, eventArgs) => {
            // 关键修复：在工具操作时冻结 widget 更新，避免触发任何刷新或 pipeline 检查
            let wasFrozen = false;
            try {
              if (widget && widget.setOptions) {
                wasFrozen = widget.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }

            try {
              const selection = eventArgs.getSelection();
              const length = selection.length;

              if (length === 0) {
                // 点击空白区域，取消选中
                if (this.annotationToolBottom && this.annotationToolBottom.getMode() === PaintMode.Edit) {
                  this.annotationToolBottom.editNode(null);
                }
                if (this.pencilToolBottom && this.pencilToolBottom.getMode() === PaintMode.Edit) {
                  this.pencilToolBottom.editNode(null);
                  // 如果线条工具面板是激活的，切换回创建模式，允许继续绘制新线条
                  if (this.showLineStylePanel && this.pencilToolBottom.isEnabled()) {
                    this.pencilToolBottom.setEditMode(EditMode.Create);
                  }
                }
              } else if (length > 0) {
                // 选中了节点，根据节点类型决定使用哪个工具
                const selectedNode = selection[length - 1];

                // 检查节点是否是文本节点
                const isTextNode = (selectedNode.text !== undefined && selectedNode.text !== null) ||
                  (typeof selectedNode.getText === 'function');

                // 检查节点是否是路径节点（线条）
                const isPathNode = selectedNode.getType && selectedNode.getType() === 'Path' ||
                  (selectedNode.getProperties && selectedNode.getProperties().linestyle);

                if (isTextNode && this.annotationToolBottom) {
                  // 文本节点：使用 annotationToolBottom 编辑
                  if (this.annotationToolBottom.getMode() !== PaintMode.Edit || this.annotationToolBottom.getShape() !== selectedNode) {
                    this.annotationToolBottom.setEditMode(EditMode.EditNode);
                    this.annotationToolBottom.editNode(selectedNode);
                  }
                  // 如果线条工具在编辑模式，取消它
                  if (this.pencilToolBottom && this.pencilToolBottom.getMode() === PaintMode.Edit) {
                    this.pencilToolBottom.editNode(null);
                  }
                } else if (isPathNode && this.pencilToolBottom) {
                  // 路径节点（线条）：使用 pencilToolBottom 编辑
                  // 关键修复：即使 pencilToolBottom 当前未启用，也要启用它并设置为编辑模式
                  if (!this.pencilToolBottom.isEnabled()) {
                    this.pencilToolBottom.setEnabled(true);
                  }
                  if (this.pencilToolBottom.getMode() !== PaintMode.Edit || this.pencilToolBottom.getShape() !== selectedNode) {
                    this.pencilToolBottom.setEditMode(EditMode.EditNode);
                    this.pencilToolBottom.editNode(selectedNode);
                  }
                  // 如果文本工具在编辑模式，取消它
                  if (this.annotationToolBottom && this.annotationToolBottom.getMode() === PaintMode.Edit) {
                    this.annotationToolBottom.editNode(null);
                  }
                }

                eventArgs.stopPropagation(true, true);
              }
            } finally {
              // 恢复 widget 更新
              try {
                if (widget && widget.setOptions && wasFrozen !== undefined) {
                  widget.setOptions({ 'freezeupdate': false });
                }
              } catch (e) { }
            }
          });

        const toolManager = widget.getTool();
        try { toolManager.remove(this.annotationToolBottom); toolManager.remove(selectionToolBottom); } catch (e) { }
        toolManager.insert(0, selectionToolBottom);
        toolManager.insert(0, this.annotationToolBottom);

        // 监听文本结束，缓存并打上 panel 标记为 bottom
        this.annotationToolBottom.addListener(EditEvents.End, (tool, node) => {
          if (!node) return;
          let text = '';
          if (node.text && String(node.text).trim() !== '') text = String(node.text);
          if (!text && typeof node.getText === 'function') {
            try { const t = node.getText(); if (t && String(t).trim() !== '') text = String(t); } catch (e) { }
          }
          if (!text && typeof node.getProperties === 'function') {
            try { const p = node.getProperties(); if (p && p.text && String(p.text).trim() !== '') text = String(p.text); } catch (e) { }
          }
          if (text) {
            const props = node.getProperties ? node.getProperties() : {};
            // 确保 properties.text 有值
            try { if (typeof node.setProperties === 'function') node.setProperties({ ...props, text }); } catch (e) { }
            // 写入缓存（带面板标记）
            try {
              const textStyle = node.getTextStyle ? node.getTextStyle() : null;
              const cacheItem = {
                type: 'text',
                text,
                properties: node.getProperties ? node.getProperties() : {},
                textStyle: textStyle ? {
                  font: textStyle.getFont && textStyle.getFont(),
                  color: textStyle.getColor && textStyle.getColor(),
                  size: textStyle.size,
                  alignment: textStyle.getAlignment && textStyle.getAlignment()
                } : null,
                panel: 'bottom',
                _nodeRef: node
              };
              const idx = this.collectedAnnotations.findIndex(it => it._nodeRef === node);
              if (idx >= 0) this.collectedAnnotations[idx] = cacheItem; else this.collectedAnnotations.push(cacheItem);
            } catch (e) { }
          }
          if (this.annotationsBottom.indexOfChild(node) === -1) this.annotationsBottom.addChild(node);
          // 移除频繁的 invalidate 调用，避免闪烁
          // 工具绘制完成后，widget 会自动更新，不需要手动刷新
          // try { widget.invalidate && widget.invalidate(); } catch (e) { }
        });

        // 线条工具（底部）
        const lineStyle = new LineStyle({ color: this.lineStyle?.color || '#0351ad', width: this.lineStyle?.width || 2, pattern: this.getProcessedLinePattern ? this.getProcessedLinePattern(this.lineStyle?.pattern) : [] });
        this.pencilToolBottom = new Paint({
          'layer': widget.getManipulatorLayer(),
          'mode': PaintMode.Pencil,
          'editmode': EditMode.Create,
          'node': { 'linestyle': lineStyle, 'selectable': true, 'movable': true, 'editable': true }
        });
        this.pencilToolBottom
          .addListener(EditEvents.Start, (tool, command) => { const node = command.getNode(); if (node) this.annotationsBottom.addChild(node); })
          .addListener(EditEvents.End, (tool, node) => {
            if (!node) return;
            try {
              const props = node.getProperties ? node.getProperties() : {};
              this.collectedAnnotations.push({ type: 'path', properties: props, panel: 'bottom', _nodeRef: node });
            } catch (e) { }
            if (this.annotationsBottom.indexOfChild(node) === -1) this.annotationsBottom.addChild(node);

            // 关键修复：绘制完成后，确保节点保持可编辑属性
            try {
              const props = typeof node.getProperties === 'function' ? node.getProperties() : {};
              if (!props.selectable || !props.movable || !props.editable) {
                // 如果属性丢失，重新设置
                const currentLineStyle = props.linestyle || new LineStyle({
                  color: this.lineStyle?.color || '#0351ad',
                  width: this.lineStyle?.width || 2,
                  pattern: this.getProcessedLinePattern ? this.getProcessedLinePattern(this.lineStyle?.pattern) : []
                });
                node.setProperties({
                  ...props,
                  linestyle: currentLineStyle,
                  selectable: true,
                  movable: true,
                  editable: true
                });
              }
            } catch (e) {
              console.warn('设置底部线条节点编辑属性失败:', e);
            }

            // 修复：绘制完成后，保持编辑模式，让用户可以立即编辑刚绘制的线条
            try {
              if (this.pencilToolBottom && this.pencilToolBottom.isEnabled() && this.showLineStylePanel) {
                // 设置编辑模式，让用户可以选择和编辑刚绘制的线条
                this.pencilToolBottom.setEditMode(EditMode.EditNode);
                this.pencilToolBottom.editNode(node);
              }
            } catch (e) {
              console.warn('设置底部线条编辑模式失败:', e);
            }
          });

        // 默认禁用，按按钮再启用
        try { this.annotationToolBottom.setEnabled(false); this.annotationToolBottom.editNode(null); } catch (e) { }
        try { this.pencilToolBottom.setEnabled(false); } catch (e) { }
      } catch (e) {
        console.warn('initAnnotationToolsBottom error:', e);
      }
    },

    // 在工具切换或面板开启时，确保底部显示绑定当前pipeline
    refreshBottomDisplay() {
      try {
        if (this._seismicWidgetBottom && this.pipelineBottom) {
          // 只有在 pipeline 确实需要更新时才调用 setPipeline，避免不必要的刷新
          // 检查当前 pipeline 是否已经是正确的
          const currentPipeline = this._seismicWidgetBottom.getPipeline && this._seismicWidgetBottom.getPipeline();
          if (currentPipeline !== this.pipelineBottom) {
            // 关键修复：使用 freezeupdate 避免刷新时的闪烁
            let wasFrozen = false;
            try {
              if (this._seismicWidgetBottom.setOptions) {
                wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }

            try {
              this._seismicWidgetBottom.setPipeline(this.pipelineBottom);
            } catch (e) { }

            // 恢复更新
            try {
              if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
              }
            } catch (e) { }

            // 只有在 pipeline 改变时才刷新
            try {
              this.$nextTick(() => {
                if (this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate) {
                  this._seismicWidgetBottom.invalidate();
                }
              });
            } catch (e) { }
          }
        }
      } catch (e) { /* ignore */ }
    },

    // 计算当前索引应展示的底部数据键和值
    getExpectedBottomInfo() {
      const segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0) ? this.ysqqXmxxSegy : this.segyList;
      const item = Array.isArray(segList) ? segList[this.currentSegyIndex] : null;
      if (!item) return null;
      const path = item.xbsegy || '';
      const name = item.xbsegyName || this.extractFileName(item.xbsegy || '') || 'xbsegy';
      return { path, name };
    },

    // 若底部当前绑定不是当前索引的数据，则立即更正
    async assertBottomPipelineCurrent() {
      try {
        const info = this.getExpectedBottomInfo();
        if (!info || !info.path) return;

        // 关键修复：如果路径和名称都匹配，不需要做任何操作，直接返回，避免任何刷新
        // 使用严格相等比较，确保不会因为类型不同而误判
        if (String(this._bottomSegyPath) === String(info.path) && String(this._bottomSegyKey) === String(info.name)) {
          return;
        }

        // 关键修复：在切换 pipeline 前冻结 widget 更新，避免闪烁
        let wasFrozen = false;
        try {
          if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
            wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
          }
        } catch (e) { }

        // 优先用路径判断是否一致
        if (!this._bottomSegyPath || String(this._bottomSegyPath) !== String(info.path)) {
          // 使用 skipRefresh=true 并手动控制刷新，避免不必要的刷新
          await this.loadSegyIntoWidget('bottom', info.path, info.name, true);
          // 恢复 widget 更新
          try {
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
            // 只在真正需要时才刷新一次
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate) {
              this.$nextTick(() => {
                try {
                  this._seismicWidgetBottom.invalidate();
                } catch (e) { }
              });
            }
          } catch (e) { }
          return;
        }
        // 其次用名称兜底（通常不会走到这里，因为路径已匹配）
        const expectedKey = info.name;
        if (!this._bottomSegyKey || String(this._bottomSegyKey) !== String(expectedKey)) {
          await this.loadSegyIntoWidget('bottom', info.path, info.name, true);
          // 恢复 widget 更新
          try {
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate) {
              this.$nextTick(() => {
                try {
                  this._seismicWidgetBottom.invalidate();
                } catch (e) { }
              });
            }
          } catch (e) { }
        } else {
          // 如果只是名称不匹配但路径匹配，直接恢复更新，不需要重新加载
          try {
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
          } catch (e) { }
        }
      } catch (e) {
        // 确保即使出错也恢复更新
        try {
          if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
            this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
          }
        } catch (e2) { }
      }
    },

    // 同步滚动条（左右与上下）- 防死循环版本
    onScroll(origin) {
      // 多重防护：防止死循环
      if (this._isSyncingScroll || this._scrollSyncTimeout) return;

      const topEl = this.$refs.topScroll;
      const bottomEl = this.$refs.bottomScroll;
      if (!topEl || !bottomEl) return;

      // 设置同步标志和超时保护
      this._isSyncingScroll = true;

      // 使用 requestAnimationFrame 确保在下一帧执行，避免同步冲突
      this._scrollSyncTimeout = requestAnimationFrame(() => {
        try {
          if (origin === 'top') {
            // 检查是否需要同步，避免无意义的赋值
            if (bottomEl.scrollLeft !== topEl.scrollLeft || bottomEl.scrollTop !== topEl.scrollTop) {
              bottomEl.scrollLeft = topEl.scrollLeft;
              bottomEl.scrollTop = topEl.scrollTop;
            }
          } else if (origin === 'bottom') {
            // 检查是否需要同步，避免无意义的赋值
            if (topEl.scrollLeft !== bottomEl.scrollLeft || topEl.scrollTop !== bottomEl.scrollTop) {
              topEl.scrollLeft = bottomEl.scrollLeft;
              topEl.scrollTop = bottomEl.scrollTop;
            }
          }
        } catch (error) {
          console.warn('滚动同步出错:', error);
        } finally {
          // 清理标志，使用 setTimeout 确保在下一个事件循环中清理
          setTimeout(() => {
            this._isSyncingScroll = false;
            this._scrollSyncTimeout = null;
          }, 0);
        }
      });
    },

    // 让顶部/底部视图缩放同步
    ensureZoomSyncHook() {
      if (this._zoomHooked) return;
      const top = this._seismicWidget;
      const bottom = this._seismicWidgetBottom;
      if (!top || !bottom || !top.setModelLimits || !bottom.setModelLimits) return;

      try {
        const self = this;
        const originalTop = top.setModelLimits.bind(top);
        const originalBottom = bottom.setModelLimits.bind(bottom);

        top.setModelLimits = function (rect) {
          const result = originalTop(rect);
          // 修复：避免在工具操作时触发底部图的刷新，防止闪烁
          // 移除跨 widget 的自动刷新，避免点击一个图时另一个图闪烁
          if (!self._isSyncingZoom) {
            self._isSyncingZoom = true;
            try {
              originalBottom(rect);
              // 关键修复：移除自动刷新底部图，避免点击顶部图时底部图闪烁
              // 工具操作（绘制、点击等）不应该触发跨 widget 的刷新
              // if (bottom.invalidate) bottom.invalidate();
              if (self.updateWidgetScrollbar) self.updateWidgetScrollbar(bottom);
              // 使用CSS方法彻底禁用内部滚动条
              if (self.setScrollbarCSS) self.setScrollbarCSS(bottom);
              // 更新外层滚动区域尺寸（只在非初始加载时）
              if (self.updateScrollAreaSize && !self._isInitialLoad) {
                self.updateScrollAreaSize();
              }
            } finally {
              self._isSyncingZoom = false;
            }
          }
          return result;
        };

        bottom.setModelLimits = function (rect) {
          const result = originalBottom(rect);
          // 关键修复：避免在工具操作时触发顶部图的刷新，防止闪烁
          // 移除跨 widget 的自动刷新，这是导致点击底部图时顶部图闪烁的根本原因
          if (!self._isSyncingZoom) {
            self._isSyncingZoom = true;
            try {
              originalTop(rect);
              // 关键修复：移除自动刷新顶部图，避免点击底部图时顶部图闪烁
              // 工具操作（绘制、点击等）不应该触发跨 widget 的刷新
              // if (top.invalidate) top.invalidate();
              if (self.updateWidgetScrollbar) self.updateWidgetScrollbar(top);
              // 使用CSS方法彻底禁用内部滚动条
              if (self.setScrollbarCSS) self.setScrollbarCSS(top);
              // 更新外层滚动区域尺寸（只在非初始加载时）
              if (self.updateScrollAreaSize && !self._isInitialLoad) {
                self.updateScrollAreaSize();
              }
            } finally {
              self._isSyncingZoom = false;
            }
          }
          return result;
        };

        this._zoomHooked = true;
      } catch (e) {
        console.warn('设置缩放同步钩子失败:', e);
      }
    },

    // 更新内部滚动条工具
    updateWidgetScrollbar(widget) {
      try {
        const toolManager = widget && widget.getTool && widget.getTool();
        if (!toolManager || !toolManager.getScrollbarTool) return;
        const scrollbarTool = toolManager.getScrollbarTool();
        if (scrollbarTool && scrollbarTool.update) scrollbarTool.update();
      } catch (e) {
        // ignore
      }
    },

    // 强制禁用内部滚动条
    forceDisableInternalScrollbars(widget) {
      if (!widget) return;

      try {
        // 方法1: 通过工具管理器禁用
        const toolManager = widget.getTool && widget.getTool();
        if (toolManager) {
          if (toolManager.getScrollbarTool) {
            const scrollbarTool = toolManager.getScrollbarTool();
            if (scrollbarTool) {
              try { scrollbarTool.setEnabled(false); } catch (e) { }
              try { scrollbarTool.setVisible && scrollbarTool.setVisible(false); } catch (e) { }
              try { scrollbarTool.setActive && scrollbarTool.setActive(false); } catch (e) { }
            }
          }

          // 尝试移除滚动条工具
          if (toolManager.remove) {
            try {
              const tools = toolManager.getTools && toolManager.getTools();
              if (tools) {
                tools.forEach(tool => {
                  if (tool && tool.getType && tool.getType() === 'scrollbar') {
                    toolManager.remove(tool);
                  }
                });
              }
            } catch (e) { }
          }
        }

        // 方法2: 通过widget选项禁用
        try {
          widget.setOptions({
            'tools': {
              'scrollbar': {
                'enabled': false,
                'visible': false,
                'active': false
              }
            }
          });
        } catch (e) { }

        // 方法3: 通过DOM操作隐藏滚动条
        setTimeout(() => {
          try {
            const canvas = widget.getCanvas && widget.getCanvas();
            if (canvas) {
              const container = canvas.parentElement;
              if (container) {
                // 隐藏所有可能的滚动条元素
                const scrollbars = container.querySelectorAll('.gt-scrollbar, .scrollbar, [class*="scrollbar"]');
                scrollbars.forEach(sb => {
                  sb.style.display = 'none';
                  sb.style.visibility = 'hidden';
                  sb.style.pointerEvents = 'none';
                  sb.style.opacity = '0';
                  sb.style.width = '0';
                  sb.style.height = '0';
                });
              }
            }
          } catch (e) { }
        }, 100);

        //console.log('内部滚动条已强制禁用');
      } catch (error) {
        console.warn('禁用内部滚动条时出错:', error);
      }
    },

    // 定期检查并禁用内部滚动条
    startScrollbarMonitor() {
      if (this._scrollbarMonitorInterval) {
        clearInterval(this._scrollbarMonitorInterval);
      }

      // 只执行一次，不循环
      try {
        // 使用CSS方法彻底禁用顶部widget的滚动条
        if (this._seismicWidget) {
          this.setScrollbarCSS(this._seismicWidget);
          this.disableWidgetScrollbar(this._seismicWidget);
        }

        // 使用CSS方法彻底禁用底部widget的滚动条
        if (this._seismicWidgetBottom) {
          this.setScrollbarCSS(this._seismicWidgetBottom);
          this.disableWidgetScrollbar(this._seismicWidgetBottom);
        }

        // 通过DOM检查隐藏任何出现的滚动条（仅限本页面容器内）
        const rootEl = this.$el || document;
        const allScrollbars = (rootEl.querySelectorAll ? rootEl.querySelectorAll('.sync-section .gt-scrollbar, .sync-section .scrollbar, .sync-section [class*="scrollbar"], .sync-section [class*="Scroll"], .sync-section [class*="scroll"], .sync-section [class*="geotoolkit.controls.tools.scroll"]') : []);
        allScrollbars.forEach(sb => {
          if (sb.style.display !== 'none') {
            sb.style.display = 'none';
            sb.style.visibility = 'hidden';
            sb.style.pointerEvents = 'none';
            sb.style.opacity = '0';
            sb.style.width = '0';
            sb.style.height = '0';
            sb.style.position = 'absolute';
            sb.style.left = '-9999px';
            sb.style.top = '-9999px';
          }
        });

        //console.log('滚动条监控已执行一次');
      } catch (e) {
        console.warn('滚动条监控失败:', e);
      }
    },

    // 停止滚动条监控
    stopScrollbarMonitor() {
      if (this._scrollbarMonitorInterval) {
        clearInterval(this._scrollbarMonitorInterval);
        this._scrollbarMonitorInterval = null;
      }
    },

    // 使用CSS方法彻底禁用内部滚动条
    setScrollbarCSS(widget) {
      if (!widget || !widget.setCss) return;

      try {
        const css = [
          // 隐藏水平滚动条 - 使用GeoToolkit的实际类名
          '*[class="geotoolkit.controls.tools.scroll.HorizontalScroll"] {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  pointer-events: none !important;',
          '  position: absolute !important;',
          '  left: -9999px !important;',
          '  top: -9999px !important;',
          '}',
          // 隐藏垂直滚动条 - 使用GeoToolkit的实际类名
          '*[class="geotoolkit.controls.tools.scroll.VerticalScroll"] {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  pointer-events: none !important;',
          '  position: absolute !important;',
          '  left: -9999px !important;',
          '  top: -9999px !important;',
          '}',
          // 隐藏所有可能的滚动条相关元素
          '.gt-scrollbar,',
          '.gt-scrollbar-horizontal,',
          '.gt-scrollbar-vertical,',
          '[class*="scrollbar"],',
          '[class*="Scrollbar"],',
          '.scrollbar,',
          '.scrollbar-horizontal,',
          '.scrollbar-vertical,',
          '[class*="Scroll"],',
          '[class*="scroll"] {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  pointer-events: none !important;',
          '  position: absolute !important;',
          '  left: -9999px !important;',
          '  top: -9999px !important;',
          '}',
          // 隐藏滚动条滑块和轨道
          '.scrollbar-thumb,',
          '.scrollbar-track,',
          '.gt-scrollbar-thumb,',
          '.gt-scrollbar-track,',
          '[class*="thumb"],',
          '[class*="track"] {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  pointer-events: none !important;',
          '}',
          // 确保滚动条容器也被隐藏
          '[class*="scroll-container"],',
          '[class*="ScrollContainer"],',
          '.scroll-container {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  pointer-events: none !important;',
          '}',
          // 新增：隐藏 GeoToolkit-js 2.0 特有的滚动条元素
          '[class*="geotoolkit.controls.tools.scroll"],',
          '[class*="ScrollTool"],',
          '[class*="scroll-tool"],',
          '[class*="ScrollBar"],',
          '[class*="scroll-bar"],',
          '[class*="ScrollbarTool"],',
          '[class*="scrollbar-tool"] {',
          '  display: none !important;',
          '  visibility: hidden !important;',
          '  opacity: 0 !important;',
          '  width: 0 !important;',
          '  height: 0 !important;',
          '  position: absolute !important;',
          '  left: -9999px !important;',
          '  top: -9999px !important;',
          '  pointer-events: none !important;',
          '}',
          // 新增：隐藏可能的滚动条容器和包装器
          '[class*="scroll-wrapper"],',
          '[class*="ScrollWrapper"],',
          '[class*="scroll-area"],',
          '[class*="ScrollArea"] {',
          '  overflow: hidden !important;',
          '}'
        ].join('\n');

        widget.setCss(css);
        //console.log('已通过CSS方法彻底禁用内部滚动条');
      } catch (error) {
        console.warn('设置滚动条CSS失败:', error);
      }
    },

    // 强制同步内部滚动条（如果必须保留内部滚动条）
    enableInternalScrollbarSync() {
      if (!this._seismicWidget || !this._seismicWidgetBottom) return;

      try {
        // 彻底禁用内部滚动条
        this.forceDisableInternalScrollbars();
        // 强制隐藏所有内部滚动条
        this.forceHideAllInternalScrollbars();
        // 设置外层滚动条同步
        this.setupOuterScrollbarSync();
        // 启动外层滚动条同步监控
        this.startOuterScrollbarSyncMonitor();
        //console.log('已彻底禁用内部滚动条并启用外层滚动条同步')
      } catch (error) {
        console.warn('启用外层滚动条同步失败:', error);
      }
    },

    // 设置外层滚动条同步（GeoToolkit 3.2.80兼容模式）
    setupOuterScrollbarSync() {
      if (!this._seismicWidget || !this._seismicWidgetBottom) return;
      try {
        // 清除之前的监听器
        this.clearOuterScrollbarListeners();
        // 获取外层滚动容器
        const topContainer = this.getOuterScrollContainer(this._seismicWidget);
        const bottomContainer = this.getOuterScrollContainer(this._seismicWidgetBottom);

        if (!topContainer || !bottomContainer) {
          console.warn('未找到外层滚动容器');
          return;
        }

        // 创建防抖的同步函数
        this._syncFromTopOuter = this.debounce((event) => {
          try {
            if (this._isSyncingOuterScroll) return;
            this._isSyncingOuterScroll = true;

            // 同步到底部容器
            bottomContainer.scrollLeft = topContainer.scrollLeft;
            bottomContainer.scrollTop = topContainer.scrollTop;

            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidgetBottom, topContainer.scrollLeft, topContainer.scrollTop);

            setTimeout(() => {
              this._isSyncingOuterScroll = false;
            }, 10);
          } catch (e) {
            console.warn('同步外层滚动位置失败:', e);
            this._isSyncingOuterScroll = false;
          }
        }, 5);

        this._syncFromBottomOuter = this.debounce((event) => {
          try {
            if (this._isSyncingOuterScroll) return;
            this._isSyncingOuterScroll = true;

            // 同步到顶部容器
            topContainer.scrollLeft = bottomContainer.scrollLeft;
            topContainer.scrollTop = bottomContainer.scrollTop;

            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidget, bottomContainer.scrollLeft, bottomContainer.scrollTop);

            setTimeout(() => {
              this._isSyncingOuterScroll = false;
            }, 10);
          } catch (e) {
            console.warn('同步外层滚动位置失败:', e);
            this._isSyncingOuterScroll = false;
          }
        }, 5);

        // 监听顶部容器的滚动事件
        topContainer.addEventListener('scroll', this._syncFromTopOuter);
        this._outerScrollListeners.push({ element: topContainer, event: 'scroll', handler: this._syncFromTopOuter });

        // 监听底部容器的滚动事件
        bottomContainer.addEventListener('scroll', this._syncFromBottomOuter);
        this._outerScrollListeners.push({ element: bottomContainer, event: 'scroll', handler: this._syncFromBottomOuter });

        //console.log('外层滚动条同步已设置（GeoToolkit 3.2.80兼容模式）');
      } catch (error) {
        console.warn('设置外层滚动条同步失败:', error);
      }
    },

    // 清除外层滚动条监听器
    clearOuterScrollbarListeners() {
      try {
        if (this._outerScrollListeners) {
          this._outerScrollListeners.forEach(({ element, event, handler }) => {
            if (element && element.removeEventListener) {
              element.removeEventListener(event, handler);
            }
          });
          this._outerScrollListeners = [];
        }
      } catch (e) {
        console.warn('清除外层滚动条监听器失败:', e);
      }
    },

    // 防抖函数
    debounce(func, wait) {
      let timeout;
      return function executedFunction(...args) {
        const later = () => {
          clearTimeout(timeout);
          func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
      };
    },

    // 设置DOM级别的滚动条同步
    setupDOMScrollbarSync() {
      try {
        // 清除之前的DOM监听器
        this.clearDOMScrollbarListeners();

        // 获取滚动条DOM元素
        const topScrollbars = this.findScrollbarElements(this._seismicWidget);
        const bottomScrollbars = this.findScrollbarElements(this._seismicWidgetBottom);

        if (topScrollbars.length === 0 || bottomScrollbars.length === 0) {
          //console.log('未找到滚动条DOM元素，跳过DOM同步');
          return;
        }

        // 为顶部滚动条添加事件监听
        topScrollbars.forEach(scrollbar => {
          const onTopScroll = this.debounce((event) => {
            if (this._isSyncingDOMScroll) return;
            this._isSyncingDOMScroll = true;

            // 同步到底部滚动条
            bottomScrollbars.forEach(bottomScrollbar => {
              if (bottomScrollbar.scrollLeft !== undefined) {
                bottomScrollbar.scrollLeft = scrollbar.scrollLeft;
              }
              if (bottomScrollbar.scrollTop !== undefined) {
                bottomScrollbar.scrollTop = scrollbar.scrollTop;
              }
            });

            setTimeout(() => {
              this._isSyncingDOMScroll = false;
            }, 10);
          }, 5);

          scrollbar.addEventListener('scroll', onTopScroll);
          this._domScrollListeners.push({ element: scrollbar, event: 'scroll', handler: onTopScroll });
        });

        // 为底部滚动条添加事件监听
        bottomScrollbars.forEach(scrollbar => {
          const onBottomScroll = this.debounce((event) => {
            if (this._isSyncingDOMScroll) return;
            this._isSyncingDOMScroll = true;

            // 同步到顶部滚动条
            topScrollbars.forEach(topScrollbar => {
              if (topScrollbar.scrollLeft !== undefined) {
                topScrollbar.scrollLeft = scrollbar.scrollLeft;
              }
              if (topScrollbar.scrollTop !== undefined) {
                topScrollbar.scrollTop = scrollbar.scrollTop;
              }
            });

            setTimeout(() => {
              this._isSyncingDOMScroll = false;
            }, 10);
          }, 5);

          scrollbar.addEventListener('scroll', onBottomScroll);
          this._domScrollListeners.push({ element: scrollbar, event: 'scroll', handler: onBottomScroll });
        });

        //console.log('DOM级别滚动条同步已设置');
      } catch (e) {
        console.warn('设置DOM滚动条同步失败:', e);
      }
    },
    // 获取外层滚动容器（GeoToolkit 3.2.80兼容）
    getOuterScrollContainer(widget) {
      try {
        if (!widget || !widget.getCanvas) return null;

        const canvas = widget.getCanvas();
        if (!canvas) return null;

        // 查找包含widget的滚动容器
        let container = canvas.parentElement;
        while (container && container !== document.body) {
          // 检查容器是否有滚动能力
          if (container.scrollWidth > container.clientWidth ||
            container.scrollHeight > container.clientHeight) {
            return container;
          }

          // 检查容器是否有overflow: auto/scroll样式
          const style = window.getComputedStyle(container);
          if (style.overflow === 'auto' || style.overflow === 'scroll' ||
            style.overflowX === 'auto' || style.overflowX === 'scroll' ||
            style.overflowY === 'auto' || style.overflowY === 'scroll') {
            return container;
          }

          container = container.parentElement;
        }

        // 如果没有找到滚动容器，返回canvas的直接父容器
        return canvas.parentElement;
      } catch (e) {
        console.warn('获取外层滚动容器失败:', e);
        return null;
      }
    },

    // 同步GeoToolkit内部视图（GeoToolkit 3.2.80兼容）
    syncGeoToolkitView(widget, scrollLeft, scrollTop) {
      try {
        if (!widget) return;

        // 方法1: 通过setViewport同步
        if (widget.setViewport) {
          const viewport = widget.getViewport();
          if (viewport) {
            // 计算新的视图位置
            const newViewport = {
              x: scrollLeft || 0,
              y: scrollTop || 0,
              width: viewport.width || 800,
              height: viewport.height || 600
            };
            widget.setViewport(newViewport);
          }
        }

        // 方法2: 通过setPosition同步
        if (widget.setPosition) {
          widget.setPosition(scrollLeft || 0, scrollTop || 0);
        }

        // 方法3: 通过工具管理器同步
        if (widget.getTool) {
          const toolManager = widget.getTool();
          if (toolManager && toolManager.setPosition) {
            toolManager.setPosition(scrollLeft || 0, scrollTop || 0);
          }
        }

        // 方法4: 通过Plot同步
        if (widget.getPlot) {
          const plot = widget.getPlot();
          if (plot && plot.setViewport) {
            const viewport = plot.getViewport();
            if (viewport) {
              const newViewport = {
                x: scrollLeft || 0,
                y: scrollTop || 0,
                width: viewport.width || 800,
                height: viewport.height || 600
              };
              plot.setViewport(newViewport);
            }
          }
        }

        // 强制重绘
        if (widget.invalidate) {
          widget.invalidate();
        }

      } catch (e) {
        console.warn('同步GeoToolkit内部视图失败:', e);
      }
    },

    // 启动外层滚动条同步监控（GeoToolkit 3.2.80兼容）
    startOuterScrollbarSyncMonitor() {
      if (this._outerScrollbarSyncInterval) {
        clearInterval(this._outerScrollbarSyncInterval);
      }

      this._outerScrollbarSyncInterval = setInterval(() => {
        try {
          this.forceOuterScrollbarSync();
        } catch (e) {
          console.warn('外层滚动条同步监控失败:', e);
        }
      }, 50); // 每50ms检查一次，提高响应性
    },

    // 强制外层滚动条同步（GeoToolkit 3.2.80兼容）
    forceOuterScrollbarSync() {
      try {
        if (!this._seismicWidget || !this._seismicWidgetBottom) return;

        // 获取两个widget的外层滚动容器
        const topContainer = this.getOuterScrollContainer(this._seismicWidget);
        const bottomContainer = this.getOuterScrollContainer(this._seismicWidgetBottom);

        if (!topContainer || !bottomContainer) return;

        // 检查是否有滚动位置不同步
        if (topContainer.scrollLeft !== bottomContainer.scrollLeft) {
          if (this._lastTopScrollLeft !== topContainer.scrollLeft) {
            bottomContainer.scrollLeft = topContainer.scrollLeft;
            this._lastTopScrollLeft = topContainer.scrollLeft;
            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidgetBottom, topContainer.scrollLeft, topContainer.scrollTop);
          } else if (this._lastBottomScrollLeft !== bottomContainer.scrollLeft) {
            topContainer.scrollLeft = bottomContainer.scrollLeft;
            this._lastBottomScrollLeft = bottomContainer.scrollLeft;
            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidget, bottomContainer.scrollLeft, bottomContainer.scrollTop);
          }
        }

        if (topContainer.scrollTop !== bottomContainer.scrollTop) {
          if (this._lastTopScrollTop !== topContainer.scrollTop) {
            bottomContainer.scrollTop = topContainer.scrollTop;
            this._lastTopScrollTop = topContainer.scrollTop;
            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidgetBottom, topContainer.scrollLeft, topContainer.scrollTop);
          } else if (this._lastBottomScrollTop !== bottomContainer.scrollTop) {
            topContainer.scrollTop = bottomContainer.scrollTop;
            this._lastBottomScrollTop = bottomContainer.scrollTop;
            // 同步GeoToolkit内部视图
            this.syncGeoToolkitView(this._seismicWidget, bottomContainer.scrollLeft, bottomContainer.scrollTop);
          }
        }
      } catch (e) {
        console.warn('强制外层滚动条同步失败:', e);
      }
    },

    // 停止外层滚动条同步监控
    stopOuterScrollbarSyncMonitor() {
      if (this._outerScrollbarSyncInterval) {
        clearInterval(this._outerScrollbarSyncInterval);
        this._outerScrollbarSyncInterval = null;
      }
    },

    // 强制隐藏所有内部滚动条
    forceHideAllInternalScrollbars() {
      try {
        // 方法1: 禁用widget滚动条
        if (this._seismicWidget) {
          this.disableWidgetScrollbar(this._seismicWidget);
        }
        if (this._seismicWidgetBottom) {
          this.disableWidgetScrollbar(this._seismicWidgetBottom);
        }

        // 方法2: （禁用）不再对全局DOM进行强制隐藏
        // this.forceHideAllScrollbars();

        // 方法3: （禁用）不再注入全局CSS
        // this.addGlobalScrollbarHideCSS();

        // 方法4: （禁用）不再启动强力隐藏监控
        // this.startAggressiveScrollbarHideMonitor();

        //console.log('已强制隐藏所有内部滚动条');
      } catch (e) {
        console.warn('强制隐藏内部滚动条失败:', e);
      }
    },

    // 启动强力滚动条隐藏监控
    startAggressiveScrollbarHideMonitor() {
      if (this._scrollbarHideInterval) {
        clearInterval(this._scrollbarHideInterval);
      }

      // 只执行一次，不循环
      try {
        // （禁用）不再全局隐藏滚动条
        // this.forceHideAllScrollbars();
        // this.addGlobalScrollbarHideCSS();

        // 禁用滚动条交互
        this.disableScrollbarInteractions();

        //console.log('滚动条隐藏监控已执行一次');
      } catch (e) {
        console.warn('滚动条隐藏监控失败:', e);
      }
    },

    // 禁用滚动条交互
    disableScrollbarInteractions() {
      try {
        const rootEl = this.$el || document;
        const scrollbarElements = rootEl.querySelectorAll ? rootEl.querySelectorAll('.sync-section [class*="scrollbar"], .sync-section [class*="Scrollbar"], .sync-section [class*="scroll"], .sync-section [class*="Scroll"], .sync-section [class*="geotoolkit.controls.tools.scroll"]') : [];
        scrollbarElements.forEach(element => {
          // 禁用所有交互
          element.style.pointerEvents = 'none';
          element.style.userSelect = 'none';
          element.style.touchAction = 'none';

          // 隐藏元素
          element.style.display = 'none';
          element.style.visibility = 'hidden';
          element.style.opacity = '0';
          element.style.width = '0';
          element.style.height = '0';
          element.style.position = 'absolute';
          element.style.left = '-9999px';
          element.style.top = '-9999px';
          element.style.zIndex = '-9999';

          // 禁用滚动事件
          element.addEventListener('scroll', (e) => {
            e.preventDefault();
            e.stopPropagation();
            return false;
          }, { passive: false });

          element.addEventListener('wheel', (e) => {
            e.preventDefault();
            e.stopPropagation();
            return false;
          }, { passive: false });
        });
      } catch (e) {
        console.warn('禁用滚动条交互失败:', e);
      }
    },

    // 停止滚动条隐藏监控
    stopScrollbarHideMonitor() {
      if (this._scrollbarHideInterval) {
        clearInterval(this._scrollbarHideInterval);
        this._scrollbarHideInterval = null;
      }
    },

    // 测试外层滚动条同步（GeoToolkit 3.2.80兼容）
    testOuterScrollbarSync() {
      try {
        //console.log('=== 测试外层滚动条同步 ===');

        // 获取外层滚动容器
        const topContainer = this.getOuterScrollContainer(this._seismicWidget);
        const bottomContainer = this.getOuterScrollContainer(this._seismicWidgetBottom);

        //console.log('顶部容器:', topContainer);
        //console.log('底部容器:', bottomContainer);

        if (topContainer && bottomContainer) {
          //console.log('顶部容器滚动位置:', { scrollLeft: topContainer.scrollLeft, scrollTop: topContainer.scrollTop });
          //console.log('底部容器滚动位置:', { scrollLeft: bottomContainer.scrollLeft, scrollTop: bottomContainer.scrollTop });

          // 测试同步
          const testScrollLeft = 100;
          const testScrollTop = 50;

          topContainer.scrollLeft = testScrollLeft;
          topContainer.scrollTop = testScrollTop;

          //console.log('设置顶部容器滚动位置:', { scrollLeft: testScrollLeft, scrollTop: testScrollTop });

          // 检查同步是否生效
          setTimeout(() => {
            //console.log('同步后底部容器滚动位置:', {
            //   scrollLeft: bottomContainer.scrollLeft,
            //   scrollTop: bottomContainer.scrollTop
            // });

            if (bottomContainer.scrollLeft === testScrollLeft && bottomContainer.scrollTop === testScrollTop) {
              //console.log('✅ 外层滚动条同步测试成功！');
            } else {
              //console.log('❌ 外层滚动条同步测试失败！');
            }
          }, 100);
        } else {
          //console.log('❌ 未找到外层滚动容器');
        }
      } catch (e) {
        console.error('测试外层滚动条同步失败:', e);
      }
    },

    // 测试内部滚动条是否被隐藏
    testInternalScrollbarHidden() {
      try {
        //console.log('=== 测试内部滚动条是否被隐藏 ===');

        // 查找所有可能的滚动条元素
        const scrollbarSelectors = [
          '[class*="scrollbar"]',
          '[class*="Scrollbar"]',
          '[class*="scroll"]',
          '[class*="Scroll"]',
          '[class*="geotoolkit.controls.tools.scroll"]',
          '.gt-scrollbar',
          '.scrollbar'
        ];

        let foundScrollbars = [];
        scrollbarSelectors.forEach(selector => {
          const elements = document.querySelectorAll(selector);
          elements.forEach(el => {
            if (el.offsetWidth > 0 || el.offsetHeight > 0) {
              foundScrollbars.push({
                element: el,
                selector: selector,
                visible: el.style.display !== 'none' && el.style.visibility !== 'hidden',
                dimensions: { width: el.offsetWidth, height: el.offsetHeight }
              });
            }
          });
        });

        if (foundScrollbars.length === 0) {
          //console.log('✅ 未找到任何可见的内部滚动条！');
        } else {
          //console.log('❌ 发现以下可见的内部滚动条:');
          foundScrollbars.forEach((item, index) => {
            //console.log(`${index + 1}. 选择器: ${item.selector}`);
            //console.log(`   可见性: ${item.visible ? '可见' : '隐藏'}`);
            //console.log(`   尺寸: ${item.dimensions.width}x${item.dimensions.height}`);
            //console.log(`   元素:`, item.element);
          });

          // 尝试强制隐藏这些滚动条
          foundScrollbars.forEach(item => {
            this.hideScrollbarElement(item.element);
          });

          //console.log('已尝试强制隐藏发现的滚动条');
        }
      } catch (e) {
        console.error('测试内部滚动条隐藏失败:', e);
      }
    },

    // 强制禁用内部滚动条（GeoToolkit 3.2.80兼容）
    forceDisableInternalScrollbars() {
      try {
        if (!this._seismicWidget || !this._seismicWidgetBottom) return;

        // 方法1: 通过setOptions禁用
        this._seismicWidget.setOptions({
          'tools': {
            'scrollbar': {
              'enabled': false,
              'visible': false
            }
          }
        });

        this._seismicWidgetBottom.setOptions({
          'tools': {
            'scrollbar': {
              'enabled': false,
              'visible': false
            }
          }
        });

        // 方法2: 通过工具管理器禁用
        if (this._seismicWidget.getTool) {
          const topToolManager = this._seismicWidget.getTool();
          if (topToolManager && topToolManager.setScrollbarTool) {
            const topScrollbar = topToolManager.getScrollbarTool();
            if (topScrollbar && topScrollbar.setEnabled) {
              topScrollbar.setEnabled(false);
            }
          }
        }

        if (this._seismicWidgetBottom.getTool) {
          const bottomToolManager = this._seismicWidgetBottom.getTool();
          if (bottomToolManager && bottomToolManager.setScrollbarTool) {
            const bottomScrollbar = bottomToolManager.getScrollbarTool();
            if (bottomScrollbar && bottomScrollbar.setEnabled) {
              bottomScrollbar.setEnabled(false);
            }
          }
        }

        // 方法3: 通过CSS强制隐藏
        this.addForceHideScrollbarCSS();

        //console.log('已强制禁用内部滚动条');
      } catch (error) {
        console.warn('强制禁用内部滚动条失败:', error);
      }
    },

    // 启动滚动条同步状态监控
    startScrollbarSyncStatusMonitor() {
      // 已禁用内部滚动条同步，直接返回
      return;
    },

    // 确保滚动条同步（已禁用内部同步，直接返回）
    ensureScrollbarSync() {
      return;
    },

    // 停止滚动条同步状态监控
    stopScrollbarSyncStatusMonitor() {
      if (this._scrollbarSyncStatusInterval) {
        clearInterval(this._scrollbarSyncStatusInterval);
        this._scrollbarSyncStatusInterval = null;
      }
    },

    // 添加强制隐藏滚动条的CSS（GeoToolkit 3.2.80兼容）
    addForceHideScrollbarCSS() {
      // 为避免影响全局左侧菜单，这里不再注入全局隐藏滚动条的样式。
      // 内部滚动条隐藏交由 .sync-section 作用域 CSS 与 DOM 级隐藏来完成。
      return;
    },

    // 启动强力滚动条监控
    startAggressiveScrollbarMonitor() {
      // 仅监控本页面容器，避免影响全局（菜单/标题）
      if (this._scrollbarObserver) {
        this._scrollbarObserver.disconnect();
      }

      const rootEl = this.$el || document;
      const scopeEl = rootEl.querySelector ? rootEl.querySelector('.app-container') || rootEl : rootEl;

      this._scrollbarObserver = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
          if (mutation.type === 'childList') {
            mutation.addedNodes.forEach((node) => {
              if (node.nodeType === Node.ELEMENT_NODE) {
                // 仅处理 sync-section 范围内的滚动条
                if (node.closest && !node.closest('.sync-section')) return;
                this.hideScrollbarElement(node);
                const scrollbarElements = node.querySelectorAll ? node.querySelectorAll('.sync-section [class*="scrollbar"], .sync-section [class*="Scrollbar"], .sync-section [class*="scroll"], .sync-section [class*="Scroll"], .sync-section [class*="geotoolkit.controls.tools.scroll"]') : [];
                scrollbarElements.forEach(el => this.hideScrollbarElement(el));
              }
            });
          }
        });
      });

      // 仅观察本组件范围
      try {
        this._scrollbarObserver.observe(scopeEl, { childList: true, subtree: true });
      } catch (e) { /* ignore */ }

      // 定期强制隐藏滚动条（仅限本组件范围）
      this._aggressiveScrollbarInterval = setInterval(() => {
        this.forceHideAllScrollbars(scopeEl);
        this.forceDisableInternalScrollbars();
      }, 200);
    },

    // 隐藏单个滚动条元素
    hideScrollbarElement(element) {
      if (!element || !element.classList) return;

      const classList = Array.from(element.classList);
      const isScrollbar = classList.some(cls =>
        cls.toLowerCase().includes('scrollbar') ||
        cls.toLowerCase().includes('scroll') ||
        cls.includes('geotoolkit.controls.tools.scroll')
      );

      if (isScrollbar) {
        element.style.display = 'none';
        element.style.visibility = 'hidden';
        element.style.opacity = '0';
        element.style.width = '0';
        element.style.height = '0';
        element.style.position = 'absolute';
        element.style.left = '-9999px';
        element.style.top = '-9999px';
        element.style.pointerEvents = 'none';
      }
    },

    // 强制隐藏所有滚动条（仅作用于给定根节点，默认当前组件内）
    forceHideAllScrollbars(root) {
      const rootEl = root || this.$el || document;
      const query = rootEl.querySelectorAll ? rootEl.querySelectorAll.bind(rootEl) : document.querySelectorAll.bind(document);
      const selectors = [
        '.sync-section [class*="scrollbar"]',
        '.sync-section [class*="Scrollbar"]',
        '.sync-section [class*="scroll"]',
        '.sync-section [class*="Scroll"]',
        '.sync-section [class*="geotoolkit.controls.tools.scroll"]',
        '.sync-section .gt-scrollbar',
        '.sync-section .gt-scrollbar-horizontal',
        '.sync-section .gt-scrollbar-vertical'
      ];

      selectors.forEach(selector => {
        const elements = query(selector);
        elements.forEach(element => {
          this.hideScrollbarElement(element);
        });
      });
    },

    // 停止强力滚动条监控
    stopAggressiveScrollbarMonitor() {
      if (this._scrollbarObserver) {
        this._scrollbarObserver.disconnect();
        this._scrollbarObserver = null;
      }
      if (this._aggressiveScrollbarInterval) {
        clearInterval(this._aggressiveScrollbarInterval);
        this._aggressiveScrollbarInterval = null;
      }
    },

    // 强制禁用所有滚动条
    forceDisableAllScrollbars() {
      try {
        // 禁用widget滚动条
        if (this._seismicWidget) {
          this.disableWidgetScrollbar(this._seismicWidget);
        }
        if (this._seismicWidgetBottom) {
          this.disableWidgetScrollbar(this._seismicWidgetBottom);
        }

        // 强制隐藏所有滚动条DOM元素
        this.forceHideAllScrollbars();

        // 不再注入全局隐藏滚动条CSS，避免影响布局
        // this.addGlobalScrollbarHideCSS();

        //console.log('已强制禁用所有内部滚动条');
      } catch (e) {
        console.warn('强制禁用滚动条失败:', e);
      }
    },

    // 添加全局滚动条隐藏CSS
    addGlobalScrollbarHideCSS() {
      try {
        // 检查是否已经添加过样式
        if (document.getElementById('geotoolkit-scrollbar-hide')) {
          return;
        }

        const style = document.createElement('style');
        style.id = 'geotoolkit-scrollbar-hide';
        style.textContent = `
        /* 强制隐藏所有GeoToolkit滚动条 */
        *[class*="scrollbar"],
        *[class*="Scrollbar"],
        *[class*="scroll"],
        *[class*="Scroll"],
        *[class*="geotoolkit.controls.tools.scroll"],
        .gt-scrollbar,
        .gt-scrollbar-horizontal,
        .gt-scrollbar-vertical,
        [class*="scrollbar-tool"],
        [class*="ScrollbarTool"],
        [class*="scroll-tool"],
        [class*="ScrollTool"] {
          display: none !important;
          visibility: hidden !important;
          opacity: 0 !important;
          width: 0 !important;
          height: 0 !important;
          position: absolute !important;
          left: -9999px !important;
          top: -9999px !important;
          pointer-events: none !important;
          z-index: -9999 !important;
        }
      `;
        document.head.appendChild(style);
      } catch (e) {
        console.warn('添加全局滚动条隐藏CSS失败:', e);
      }
    },

    createScene(canvas, options) {
      try {
        const autoFormat = new AutoNumberFormat(4);
        // 创建 Plot 实例，同时创建 SeismicWidget
        this.plots = new Plot({
          'canvasElement': canvas,
          'root': this._seismicWidget = new SeismicWidget(null, {
            'layouttype': 'inside',
            'tools': {
              'crosshair': {
                'enabled': true
              }
            },
            'colorbar': {
              'axis': {
                'size': 20,
                'autolabelrotation': true,
                'tickgenerator': {
                  'edge': {
                    'tickvisible': false,
                    'labelvisible': false
                  }
                }
              },
              'title': {
                'size': 0
              },
              'colorbox': {
                'size': 10
              },
              'visible': true,
              'location': ColorBarLocation.West,  // 改为左侧
              'maxheight': '80%',
              'alignment': BoxLayoutAlignment.Center,  // 改为居中对齐
              'width': 60
            },
            'statusbar': {
              'visible': true,
              'location': 'bottom',
              'alignment': 'left',
              'size': 25,
              'sections': {
                'time': {
                  'visible': true,
                  'width': '100px'
                },
                'trace': {
                  'visible': true,
                  'width': '120px'
                },
                'value': {
                  'visible': true,
                  'width': '120px'
                }
              },
              // 修改状态栏信息显示格式
              'info': (widget, x, y, sample) => {
                if (!sample) return {
                  'time': '',
                  'trace': '',
                  'value': ''
                };

                let time = '';
                let traceNumber = '';
                let value = '';

                if (sample.location && sample.location.y != null) {
                  // 深度值保持2位小数
                  time = autoFormat.format(Math.round(sample.location.y * 100) / 100.0);
                }
                if (sample.traceNumber != null) {
                  // 道集号使用原始值+1
                  traceNumber = (sample.traceNumber + 1).toString();
                }
                if (sample.sampleValue != null) {
                  // 采样值保持3位小数
                  value = sample.sampleValue.toFixed(3);
                }

                return {
                  'time': `Time: ${time}`,
                  'trace': `Trace: ${traceNumber}`,
                  'value': `Value: ${value}`
                };
              }
            },
            'axes': {
              'samples': {
                'title': {
                  'visible': false  // 先设置为false，等pipeline加载后再更新
                },
                'visible': true,
                'labelformat': '%.0f',
                'labelvisible': true,
                'tickgenerator': {
                  'edge': {
                    'tickvisible': true,
                    'labelvisible': true
                  }
                }
              },
              'headers': {
                'fields': [],  // 先设置为空数组，等pipeline加载后再更新
                'options': {
                  'minimumSpan': 100
                }
              }
            }
          })
        });

        // 初始化颜色提供者
        this.colorProvider = SeismicColors.getDefault();

        // 注册自定义颜色映射
        this.registerColorMaps(this.colorProvider);

        // 使用CSS方法彻底禁用内部滚动条
        this.setScrollbarCSS(this._seismicWidget);

        // 初始化默认的颜色映射，使用256色以获得更平滑的渐变
        this._colorMap = this.colorProvider.createNamedColorMap('WhiteBlack', 256);

        // 根据需要加载默认演示数据
        this.$nextTick(() => {
          const autoload = options && options.autoloadDemo === false ? false : this.shouldLoadDemo;
          const doAfterLoad = () => {
            // 数据加载完成后更新轴标题
            if (this.pipeline && this._seismicWidget) {
              this._seismicWidget.setOptions({
                'axes': {
                  'samples': {
                    'title': {
                      'visible': true,
                      'text': this.pipeline.getName()
                    }
                  },
                  'headers': {
                    'fields': this._headers
                  }
                }
              });
            }
            // 初始化注释工具
            this.initAnnotationTools(this._seismicWidget);

            // 初始化下半屏
            if (this.$refs.plot2) {
              this.initSecondWidget(this.$refs.plot2);
              this.ensureZoomSyncHook();
            }

            // 初始化缩放基础高度
            this.$nextTick(() => {
              this.updateBaseCanvasSize();
              // 延迟初始化滚动区域尺寸，给数据加载更多时间
              setTimeout(() => {
                // 只在用户主动操作后才更新滚动区域
                // 初始加载时不调用 updateScrollAreaSize
                //console.log('数据加载完成，保持初始尺寸');
              }, 1000);
              // 强制禁用内部滚动条
              this.forceDisableInternalScrollbars(this._seismicWidget);

              // 额外禁用滚动条工具
              this.disableScrollbarTools();

              // 启用内部滚动条同步
              this.enableInternalScrollbarSync();
            });
          };

          if (autoload) {
            this.handleFileSelect(this.plots).then(doAfterLoad);
          } else {
            // 不加载演示数据，直接走后续初始化（保持空画布）
            doAfterLoad();
          }
        });
      } catch (error) {
        this.loadingError = `创建场景失败: ${error.message}`;
        console.error('Error creating scene:', error);
      }
    },

    async handleFileSelect(plot) {
      let segys = [];

      try {
        // 使用 toDht 接口获取数据
        //console.log('[handleFileSelect] 开始获取数据，routeId:', this.routeId);
        const res = await toDht(this.routeId);
        console.log('[handleFileSelect] toDht 接口返回:', res);

        const data = (res && (res.data !== undefined ? res.data : res)) || {};
        console.log('[handleFileSelect] 解析后的数据:', data);

        // 从 ysqqXmxxSegy 数组中获取 jbsegy 字段
        segys = Array.isArray(data.ysqqXmxxSegy) ? data.ysqqXmxxSegy : [];
        console.log('[handleFileSelect] ysqqXmxxSegy 数组:', segys);

        if (segys.length === 0) {
          throw new Error('未找到 SEGY 数据');
        }

        // 保存 segys 数据到组件状态，供后续恢复标注使用
        this.ysqqXmxxSegy = segys;
        this.segyList = segys;
        this.currentSegyIndex = 0; // 重置为第一个
        console.log('[handleFileSelect] 已保存 ysqqXmxxSegy 数据，数量:', segys.length);
      } catch (error) {
        console.error('[handleFileSelect] 获取数据失败:', error);
        this.loadingError = `获取数据失败: ${error.message}`;
        throw error;
      }

      // 使用第一个 SEGY 数据的 jbsegy 字段
      const firstSegy = segys[0];
      console.log('[handleFileSelect] 第一个 SEGY 数据:', firstSegy);

      let url = firstSegy.jbsegy;
      if (url && !url.startsWith('http')) {
        url = process.env.VUE_APP_BASE_API + url;
      }
      let fileName = firstSegy.jbsegyName || 'density.segy';

      console.log('[handleFileSelect] 最终 URL:', url);
      console.log('[handleFileSelect] 文件名:', fileName);

      return fetch(url, {
        headers: {
          Authorization: "Bearer " + getToken()
        }
      })
        .then((response) => {
          if (!response.ok) {
            throw new Error(`网络请求失败: ${response.status} ${response.statusText}`);
          }
          return response.blob();
        })
        .then((blob) => {
          if (!blob || blob.size === 0) {
            throw new Error('获取到的文件数据为空');
          }

          let filesObj = new File([blob], fileName, { type: blob.type, lastModified: Date.now() });
          const file = new LocalFile(filesObj);

          const segyReader = new SegyReader(file);
          return new Promise((resolve, reject) => {
            segyReader.loadMetaData((reader) => {
              if (reader instanceof Error) {
                this.loadingError = `加载元数据失败: ${reader.message}`;
                reject(reader);
                return;
              }

              // 获取 CDP 字段
              const knownHeaders = reader.getTraceHeaderFields();
              let cdpHeader = null;
              this._headers = [];

              knownHeaders.forEach((field) => {
                if (field.getName() === 'CDP') {
                  cdpHeader = field;
                }
                this._headers.push({
                  'visible': field.getName() === 'CDP',
                  'name': field.getName(),
                  'color': 'black'
                });
              });

              // 保存reader与文件名，供下半屏使用
              this._dataReader = reader;
              this._fileName = fileName;

              reader.readDataSetStatistics((reader, statistics) => {
                if (!statistics) {
                  this.loadingError = '无法获取数据集统计信息';
                  reject(new Error('无法获取数据集统计信息'));
                  return;
                }

                // 保存statistics供下半屏使用
                this._dataStatistics = statistics;

                const pipeline = new SeismicPipeline(fileName, reader, statistics)
                  .setColorMap(this._colorMap)
                  .setOptions({
                    'normalization': {
                      'type': NormalizationType.RMS,
                      'scale': 0.4
                    },
                    'plot': {
                      'type': {
                        'Wiggle': false,
                        'InterpolatedDensity': true
                      },
                      'decimationSpacing': 5
                    },
                    'colors': {
                      'colorMap': this._colorMap
                    }
                  });

                // Set the pipeline first
                this.pipeline = pipeline;
                this._seismicWidget.setPipeline(pipeline);

                // Then set widget options
                this._seismicWidget.setOptions({
                  'axes': {
                    'headers': {
                      'fields': this._headers
                    },
                    'samples': {
                      'title': {
                        'visible': true,
                        'text': pipeline.getName()
                      }
                    }
                  }
                });

                // Now add processors one by one
                try {
                  pipeline.addTraceProcessor(new TaperFilterProcess({
                    'apply': false,
                    'name': 'TaperFilter'
                  }));
                } catch (e) {
                  console.warn('Failed to add TaperFilter:', e);
                }

                try {
                  pipeline.addTraceProcessor(new AGC({
                    'apply': false,
                    'name': 'AGC'
                  }));
                } catch (e) {
                  console.warn('Failed to add AGC:', e);
                }

                try {
                  pipeline.addTraceProcessor(new Reverse({
                    'apply': false,
                    'name': 'Reverse'
                  }));
                } catch (e) {
                  console.warn('Failed to add Reverse:', e);
                }

                // 先设置就绪状态，但不立即调用fitToBounds
                this.isWidgetReady = true;

                // 强制禁用内部滚动条
                this.forceDisableInternalScrollbars();

                // 延迟调用fitToBounds，确保初始状态稳定
                setTimeout(() => {
                  this._seismicWidget.fitToBounds();
                  //console.log('数据加载完成，调用fitToBounds');

                  // 再次确保内部滚动条被禁用
                  this.setScrollbarCSS(this._seismicWidget);
                  this.forceDisableInternalScrollbars();

                  // 再延迟标记初始加载结束
                  setTimeout(() => {
                    this._isInitialLoad = false;
                    //console.log('初始加载完成，启用滚动区域更新');

                    // 最终确认内部滚动条被禁用
                    this.setScrollbarCSS(this._seismicWidget);
                    this.forceDisableInternalScrollbars();

                    // 文件加载完成后，恢复标注
                    // 使用从 toDht 接口获取并保存的 ysqqXmxxSegy 数据
                    this.$nextTick(() => {
                      setTimeout(() => {
                        // 优先使用从 toDht 接口获取的 ysqqXmxxSegy 数据（包含 xbbznr 字段）
                        let segList = (Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0)
                          ? this.ysqqXmxxSegy  // 使用从 toDht 接口获取的原始数据
                          : this.segyList;      // 兜底使用 segyList
                        const originSegy = segList[this.currentSegyIndex] || segList[0];
                        if (originSegy) {
                          console.log('[handleFileSelect] 准备恢复标注，使用数据源:',
                            Array.isArray(this.ysqqXmxxSegy) && this.ysqqXmxxSegy.length > 0 ? 'ysqqXmxxSegy' : 'segyList',
                            'originSegy:', originSegy);
                          // 顶部：旧版（jbbznr）
                          try { this.renderAnnotationsFromJbbznr(originSegy); } catch (e) { console.warn('renderAnnotationsFromJbbznr 调用失败:', e); }
                          // 底部：新版（xbbznr）
                          this.renderAnnotationsFromXbbznr(originSegy);
                        } else {
                          console.warn('[handleFileSelect] 未找到 originSegy，无法恢复标注');
                        }
                      }, 500);
                    });
                  }, 1000);
                }, 500);
                resolve();
              });
            });
          });
        })
        .catch(error => {
          this.loadingError = `获取地震数据失败: ${error.message}`;
          console.error('Error fetching seismic data:', error);
          throw error;
        });
    },

    handleMouseMove(event) {
      if (!this._seismicWidget || !this.isHovering) return;

      // 使用内置状态栏，不需要额外的处理逻辑
    },

    onFileOpen(evt, plot, fileInfo) {
      evt.stopPropagation();
      evt.preventDefault();
      const files = evt.target.files;
      return this.handleFileSelect(this.plots);
    },

    initAnnotationTools(widget) {
      if (!this.checkWidgetStatus()) {
        console.error('Widget status check failed');
        return;
      }

      try {
        // 创建注释层
        this.annotations = new Group();
        const overlayLayer = widget.getOverlayLayer();
        if (!overlayLayer) {
          throw new Error('无法获取覆盖层');
        }
        overlayLayer.addChild(this.annotations);

        // 创建注释工具
        this.annotationTool = new Paint({
          'layer': widget.getManipulatorLayer(),
          'node': {
            'radius': 10,
            'fillstyle': new FillStyle('#c7e1f6'),
            'linestyle': new LineStyle({
              'color': '#0351ad',
              'width': 2
            }),
            'textbox': {
              'border': true,
              'borderradius': 10,
              'fixedsize': false,
              'wordwrap': true,
              'padding': 5
            },
            'selectable': true,
            'movable': true,
            'editable': true
          },
          'handles': {
            'anchor': {
              'fillstyle': new FillStyle('#8be73d'),
              'linestyle': new LineStyle('#0351ad')
            }
          }
        });

        // 添加选择工具
        const selectionTool = new Selection()
          .setNodeFilter((nodes) => nodes.filter((node) =>
            this.annotations.indexOfChild(node) >= 0))
          .addListener(SelectionEvents.onPick, (tool, eventArgs) => {
            const selection = eventArgs.getSelection();
            const length = selection.length;

            if (length === 0) {
              // 点击空白区域，取消选中
              if (this.annotationTool && this.annotationTool.getMode() === PaintMode.Edit) {
                this.annotationTool.editNode(null);
              }
              if (this.pencilTool && this.pencilTool.getMode() === PaintMode.Edit) {
                this.pencilTool.editNode(null);
                // 如果线条工具面板是激活的，切换回创建模式，允许继续绘制新线条
                if (this.showLineStylePanel && this.pencilTool.isEnabled()) {
                  this.pencilTool.setEditMode(EditMode.Create);
                }
              }
            } else if (length > 0) {
              // 选中了节点，根据节点类型决定使用哪个工具
              const selectedNode = selection[length - 1];

              // 检查节点是否是文本节点（通过检查是否有 text 属性或 getText 方法）
              const isTextNode = (selectedNode.text !== undefined && selectedNode.text !== null) ||
                (typeof selectedNode.getText === 'function');

              // 检查节点是否是路径节点（线条）
              const isPathNode = selectedNode.getType && selectedNode.getType() === 'Path' ||
                (selectedNode.getProperties && selectedNode.getProperties().linestyle);

              if (isTextNode && this.annotationTool) {
                // 文本节点：使用 annotationTool 编辑
                if (this.annotationTool.getMode() !== PaintMode.Edit || this.annotationTool.getShape() !== selectedNode) {
                  this.annotationTool.setEditMode(EditMode.EditNode);
                  this.annotationTool.editNode(selectedNode);
                  this.selectedShape = selectedNode;
                }
                // 如果线条工具在编辑模式，取消它
                if (this.pencilTool && this.pencilTool.getMode() === PaintMode.Edit) {
                  this.pencilTool.editNode(null);
                }
              } else if (isPathNode && this.pencilTool) {
                // 路径节点（线条）：使用 pencilTool 编辑
                // 关键修复：即使 pencilTool 当前未启用，也要启用它并设置为编辑模式，以便可以编辑线条
                if (!this.pencilTool.isEnabled()) {
                  this.pencilTool.setEnabled(true);
                }
                if (this.pencilTool.getMode() !== PaintMode.Edit || this.pencilTool.getShape() !== selectedNode) {
                  this.pencilTool.setEditMode(EditMode.EditNode);
                  this.pencilTool.editNode(selectedNode);
                  this.selectedShape = selectedNode;
                }
                // 如果文本工具在编辑模式，取消它
                if (this.annotationTool && this.annotationTool.getMode() === PaintMode.Edit) {
                  this.annotationTool.editNode(null);
                }
              }

              eventArgs.stopPropagation(true, true);
            }
          });

        const toolManager = widget.getTool();
        if (!toolManager) {
          throw new Error('无法获取工具管理器');
        }

        // 清除现有工具
        try {
          toolManager.remove(this.annotationTool);
          toolManager.remove(selectionTool);
        } catch (e) {
          // 忽略错误，工具可能尚未添加
        }

        // 添加工具
        toolManager.insert(0, selectionTool);
        toolManager.insert(0, this.annotationTool);

        // 添加事件监听
        this.annotationTool
          .addListener(EditEvents.Start, (tool, command) => {
            const node = command.getNode();
            if (node) {
              this.annotations.addChild(node);
              //console.log('开始编辑:', {
              //   type: node.getType ? node.getType() : '未知类型',
              //   properties: node.getProperties()
              // });
            }
          })
          .addListener(EditEvents.End, (tool, node) => {
            if (node) {
              // 修复：按优先级提取文本，即使前面的方法返回空也要继续尝试
              let text = '';

              // 方法1: 优先从 node.text 直接属性获取（最可靠）
              if (node.text !== undefined && node.text !== null && String(node.text).trim() !== '') {
                text = String(node.text);
                console.log('[annotationTool][End] ✓ 从 node.text 获取文本:', text);
              }

              // 方法2: 如果 node.text 为空，尝试 getText() 方法
              if (!text || text.trim() === '') {
                try {
                  if (typeof node.getText === 'function') {
                    const methodText = node.getText();
                    if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
                      text = String(methodText);
                      console.log('[annotationTool][End] ✓ 从 getText() 获取文本:', text);
                    }
                  }
                } catch (e) {
                  console.warn('[annotationTool][End] getText() 调用失败:', e);
                }
              }

              // 方法3: 如果还是为空，尝试从 properties 中获取
              if (!text || text.trim() === '') {
                try {
                  if (node.getProperties && typeof node.getProperties === 'function') {
                    const props = node.getProperties();
                    if (props && props.text !== undefined && props.text !== null && String(props.text).trim() !== '') {
                      text = String(props.text);
                      console.log('[annotationTool][End] ✓ 从 properties.text 获取文本:', text);
                    }
                  }
                } catch (e) {
                  console.warn('[annotationTool][End] getProperties() 调用失败:', e);
                }
              }

              // 如果文本为空，记录警告
              if (!text || text.trim() === '') {
                console.warn('[annotationTool][End] ⚠️ 警告：文本节点但 text 为空！', {
                  node,
                  nodeText: node.text,
                  hasGetText: typeof node.getText === 'function',
                  getTextResult: typeof node.getText === 'function' ? node.getText() : 'N/A',
                  properties: node.getProperties ? node.getProperties() : null
                });
              }

              const textStyle = node.getTextStyle ? node.getTextStyle() : null;
              console.log('[annotationTool][End] 绘制文本节点', {
                node,
                text,
                nodeText: node.text,
                properties: node.getProperties && node.getProperties(),
                textStyle: textStyle ? {
                  font: textStyle.getFont && textStyle.getFont(),
                  color: textStyle.getColor && textStyle.getColor(),
                  size: textStyle.size,
                  alignment: textStyle.getAlignment && textStyle.getAlignment()
                } : null
              });

              // 关键修复：如果获取到文本，立即缓存并同步到节点
              if (text && text.trim() !== '') {
                try {
                  // 1. 同步文本到 properties
                  const props = node.getProperties ? node.getProperties() : {};
                  if (!props.text || String(props.text).trim() === '') {
                    if (typeof node.setProperties === 'function') {
                      node.setProperties({ ...props, text: text });
                      console.log('[annotationTool][End] ✓ 已同步文本到 properties.text:', text);
                    }
                  }

                  // 2. 立即缓存到 collectedAnnotations（使用节点引用作为标识）
                  try {
                    // 检查是否已存在相同节点的缓存
                    const existingIndex = this.collectedAnnotations.findIndex(item => item._nodeRef === node);
                    const cacheItem = {
                      type: 'text',
                      text: text,
                      properties: node.getProperties ? node.getProperties() : {},
                      textStyle: textStyle ? {
                        font: textStyle.getFont && textStyle.getFont(),
                        color: textStyle.getColor && textStyle.getColor(),
                        size: textStyle.size,
                        alignment: textStyle.getAlignment && textStyle.getAlignment()
                      } : null,
                      panel: 'top',
                      _nodeRef: node // 保存节点引用用于后续匹配
                    };

                    if (existingIndex >= 0) {
                      // 更新现有缓存
                      this.collectedAnnotations[existingIndex] = cacheItem;
                      console.log('[annotationTool][End] ✓ 已更新缓存项 #' + existingIndex, text);
                    } else {
                      // 添加新缓存
                      this.collectedAnnotations.push(cacheItem);
                      console.log('[annotationTool][End] ✓ 已缓存文本到 collectedAnnotations:', text, '总数:', this.collectedAnnotations.length);
                    }
                  } catch (e) {
                    console.warn('[annotationTool][End] 缓存失败:', e);
                  }
                } catch (e) {
                  console.warn('[annotationTool][End] 同步文本到 properties 失败:', e);
                }
              }

              // 确保节点被添加到图层
              if (this.annotations.indexOfChild(node) === -1) {
                this.annotations.addChild(node);
                console.log('[annotationTool][End] ✓ 已添加节点到图层');
              }
            }
            this.requestRepaint();
          });

        // 初始化工具状态
        this.annotationTool.editNode(null);
        this.annotationTool.setEnabled(false);

        // 设置就绪状态
        this.isWidgetReady = true;
        //console.log('注释工具初始化完成');

        // 强制禁用底部widget的内部滚动条
        if (this._seismicWidgetBottom) {
          this.forceDisableInternalScrollbars();
        }

        // 恢复保存的标注
        this.restoreAnnotations();
      } catch (error) {
        console.error('初始化注释工具时出错:', error);
        this.loadingError = `初始化注释工具失败: ${error.message}`;
      }
    },

    async toggleDrawText() {
      if (!this.checkWidgetStatus() || !this.isWidgetReady) {
        console.warn('Widget or annotation tools not ready');
        return;
      }

      // 如果是关闭文本工具，直接禁用并返回
      if (this.isDrawingText) {
        this.isDrawingText = false;
        this.showTextStylePanel = false;
        if (this.annotationTool) {
          this.annotationTool.setEnabled(false);
          this.annotationTool.editNode(null);
        }
        if (this.annotationToolBottom) {
          try { this.annotationToolBottom.setEnabled(false); this.annotationToolBottom.editNode(null); } catch (e) { }
        }
        return;
      }

      if (!this.annotationTool) {
        console.warn('注释工具未初始化');
        return;
      }

      // 先清除线条工具，避免功能冲突
      if (this.showLineStylePanel && this.pencilTool) {
        this.deactivatePencilTool();
      }

      this.isDrawingText = true;
      this.showTextStylePanel = true;

      // 确保文本大小为22px
      this.textStyle.size = 22;

      // 创建完整的字体字符串，确保包含字体大小
      const fontString = `${this.textStyle.bold ? 'bold ' : ''}${this.textStyle.italic ? 'italic ' : ''}${this.textStyle.size}px ${this.textStyle.font}`;

      // 先设置属性
      const textProperties = {
        'editmode': EditMode.Create,
        'mode': PaintMode.Text,
        'node': {
          'textstyle': new TextStyle({
            color: this.textStyle.color,
            size: this.textStyle.size,
            font: fontString, // 使用完整的字体字符串
            alignment: this.textStyle.align,
            bold: this.textStyle.bold,
            italic: this.textStyle.italic
          }),
          'textbox': {
            'border': this.textStyle.borderRadius > 0,
            'borderradius': this.textStyle.borderRadius,
            'padding': this.textStyle.borderRadius > 0 ? this.textStyle.borderRadius : 5,
            'fixedsize': this.textStyle.fixedFont
          },
          'selectable': true,
          'movable': true,
          'editable': true,
          'preserveontextfinish': true,
          'preserveonblur': true,
          'autofocus': true,
          'sizemode': this.textStyle.fixedFont ?
            (SizeMode.FixedWidth | SizeMode.FixedHeight) :
            SizeMode.WrappedWidth
        }
      };

      //console.log('文本绘制工具配置:', textProperties);
      this.annotationTool.setProperties(textProperties);
      if (this.annotationToolBottom) {
        try { this.annotationToolBottom.setProperties(textProperties); } catch (e) { }
      }

      // 添加事件监听器来打印文本绘制数据
      this.annotationTool.addListener(EditEvents.Start, (tool, command) => {
        const node = command.getNode();
        const textStyle = node.getTextStyle ? node.getTextStyle() : null;
        // console.log('开始绘制文本:', {
        //   tool: tool.getMode(),
        //   node: {
        //     type: node.getType ? node.getType() : 'unknown',
        //     properties: node.getProperties(),
        //     bounds: node.getBounds ? node.getBounds() : null
        //   },
        //   textStyle: {
        //     font: textStyle ? textStyle.getFont() : null,
        //     color: textStyle ? textStyle.getColor() : null,
        //     size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
        //     alignment: textStyle ? textStyle.getAlignment() : null
        //   },
        //   currentToolConfig: {
        //     mode: tool.getMode(),
        //     editMode: tool.getEditMode(),
        //     isEnabled: tool.isEnabled()
        //   }
        // });
      });

      this.annotationTool.addListener(EditEvents.Change, (tool, event) => {
        const node = tool.getShape();
        if (node) {
          const textStyle = node.getTextStyle ? node.getTextStyle() : null;
          const previousState = node._previousState || {};
          //console.log('文本绘制更新:', {
          // previous: {
          //   properties: previousState.properties || {},
          //   textStyle: previousState.textStyle || {}
          // },
          //   current: {
          //     properties: node.getProperties(),
          //     bounds: node.getBounds ? node.getBounds() : null,
          //     textStyle: {
          //       font: textStyle ? textStyle.getFont() : null,
          //       color: textStyle ? textStyle.getColor() : null,
          //       size: textStyle ? textStyle.size || this.textStyle.size : this.textStyle.size,
          //       alignment: textStyle ? textStyle.getAlignment() : null
          //     }
          //   },
          //   changes: this.detectChanges(previousState, node)
          // });
          // 保存当前状态用于下次比较
          node._previousState = {
            properties: { ...node.getProperties() },
            textStyle: textStyle ? {
              font: textStyle.getFont(),
              color: textStyle.getColor(),
              size: textStyle.size,
              alignment: textStyle.getAlignment()
            } : {}
          };
        }
      });

      this.annotationTool.addListener(EditEvents.End, (tool, node) => {
        if (node) {
          // 修复：按优先级提取文本，即使前面的方法返回空也要继续尝试
          let text = '';

          // 方法1: 优先从 node.text 直接属性获取（最可靠）
          if (node.text !== undefined && node.text !== null && String(node.text).trim() !== '') {
            text = String(node.text);
            console.log('[annotationTool][End] ✓ 从 node.text 获取文本:', text);
          }

          // 方法2: 如果 node.text 为空，尝试 getText() 方法
          if (!text || text.trim() === '') {
            try {
              if (typeof node.getText === 'function') {
                const methodText = node.getText();
                if (methodText !== undefined && methodText !== null && String(methodText).trim() !== '') {
                  text = String(methodText);
                  console.log('[annotationTool][End] ✓ 从 getText() 获取文本:', text);
                }
              }
            } catch (e) {
              console.warn('[annotationTool][End] getText() 调用失败:', e);
            }
          }

          // 方法3: 如果还是为空，尝试从 properties 中获取
          if (!text || text.trim() === '') {
            try {
              if (node.getProperties && typeof node.getProperties === 'function') {
                const props = node.getProperties();
                if (props && props.text !== undefined && props.text !== null && String(props.text).trim() !== '') {
                  text = String(props.text);
                  console.log('[annotationTool][End] ✓ 从 properties.text 获取文本:', text);
                }
              }
            } catch (e) {
              console.warn('[annotationTool][End] getProperties() 调用失败:', e);
            }
          }

          // 如果文本为空，记录警告
          if (!text || text.trim() === '') {
            console.warn('[annotationTool][End] ⚠️ 警告：文本节点但 text 为空！', {
              node,
              nodeText: node.text,
              hasGetText: typeof node.getText === 'function',
              getTextResult: typeof node.getText === 'function' ? node.getText() : 'N/A',
              properties: node.getProperties ? node.getProperties() : null
            });
          }

          const textStyle = node.getTextStyle ? node.getTextStyle() : null;
          console.log('[annotationTool][End] 绘制文本节点', {
            node,
            text,
            nodeText: node.text,
            properties: node.getProperties && node.getProperties(),
            textStyle: textStyle ? {
              font: textStyle.getFont && textStyle.getFont(),
              color: textStyle.getColor && textStyle.getColor(),
              size: textStyle.size,
              alignment: textStyle.getAlignment && textStyle.getAlignment()
            } : null
          });

          // 关键修复：如果获取到文本，立即缓存并同步到节点
          if (text && text.trim() !== '') {
            try {
              // 1. 同步文本到 properties
              const props = node.getProperties ? node.getProperties() : {};
              if (!props.text || String(props.text).trim() === '') {
                if (typeof node.setProperties === 'function') {
                  node.setProperties({ ...props, text: text });
                  console.log('[annotationTool][End] ✓ 已同步文本到 properties.text:', text);
                }
              }

              // 2. 立即缓存到 collectedAnnotations（使用节点引用作为标识）
              try {
                // 检查是否已存在相同节点的缓存
                const existingIndex = this.collectedAnnotations.findIndex(item => item._nodeRef === node);
                const cacheItem = {
                  type: 'text',
                  text: text,
                  properties: node.getProperties ? node.getProperties() : {},
                  textStyle: textStyle ? {
                    font: textStyle.getFont && textStyle.getFont(),
                    color: textStyle.getColor && textStyle.getColor(),
                    size: textStyle.size,
                    alignment: textStyle.getAlignment && textStyle.getAlignment()
                  } : null,
                  panel: 'top',
                  _nodeRef: node // 保存节点引用用于后续匹配
                };

                if (existingIndex >= 0) {
                  // 更新现有缓存
                  this.collectedAnnotations[existingIndex] = cacheItem;
                  console.log('[annotationTool][End] ✓ 已更新缓存项 #' + existingIndex, text);
                } else {
                  // 添加新缓存
                  this.collectedAnnotations.push(cacheItem);
                  console.log('[annotationTool][End] ✓ 已缓存文本到 collectedAnnotations:', text, '总数:', this.collectedAnnotations.length);
                }
              } catch (e) {
                console.warn('[annotationTool][End] 缓存失败:', e);
              }
            } catch (e) {
              console.warn('[annotationTool][End] 同步文本到 properties 失败:', e);
            }
          }

          // 确保节点被添加到图层
          if (this.annotations.indexOfChild(node) === -1) {
            this.annotations.addChild(node);
            console.log('[annotationTool][End] ✓ 已添加节点到图层');
          }
        }
        this.requestRepaint();
      });

      this.annotationTool.setEnabled(true);

      // 关键修复：确保底部文本工具被正确插入到工具管理器
      // 先冻结 widget 更新，避免工具操作时的任何刷新
      if (this.annotationToolBottom && this._seismicWidgetBottom) {
        try {
          // 先检查底部 pipeline 是否需要更新（在冻结前检查，避免不必要的冻结）
          const info = this.getExpectedBottomInfo();
          const needUpdatePipeline = info && info.path &&
            (String(this._bottomSegyPath) !== String(info.path) || String(this._bottomSegyKey) !== String(info.name));

          // 如果需要更新 pipeline，先冻结，然后更新
          let wasFrozen = false;
          if (needUpdatePipeline) {
            try {
              if (this._seismicWidgetBottom.setOptions) {
                wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }

            // 只在真正需要时才更新 pipeline
            await this.assertBottomPipelineCurrent();
          } else {
            // 即使不需要更新 pipeline，也冻结一下，避免工具操作时的刷新
            try {
              if (this._seismicWidgetBottom.setOptions) {
                wasFrozen = this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }
          }

          const tm = this._seismicWidgetBottom.getTool && this._seismicWidgetBottom.getTool();
          if (tm) {
            // 先移除线条工具，避免冲突
            if (this.pencilToolBottom) {
              try {
                this.pencilToolBottom.setEnabled(false);
                tm.remove(this.pencilToolBottom);
              } catch (e) { }
            }
            // 移除文本工具（如果已存在）
            try {
              tm.remove(this.annotationToolBottom);
            } catch (e) { }
            // 插入文本工具到最前面
            tm.insert(0, this.annotationToolBottom);
            // 设置属性并启用
            this.annotationToolBottom.setProperties(textProperties);
            this.annotationToolBottom.setEnabled(true);

            // 恢复 widget 更新
            try {
              if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
              }
            } catch (e) { }
          } else {
            // 如果没有工具管理器，也要恢复更新
            try {
              if (this._seismicWidgetBottom.setOptions && wasFrozen !== undefined) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
              }
            } catch (e) { }
          }
        } catch (e) {
          console.warn('[toggleDrawText] 设置底部文本工具失败:', e);
          // 确保即使出错也恢复更新
          try {
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
          } catch (e2) { }
        }
      }
    },

    removeAnnotation() {
      if (this.annotationTool && this.annotationTool.isEnabled() &&
        this.annotationTool.getMode() === PaintMode.Edit &&
        this.annotationTool.getShape()) {
        if (Array.isArray(this.annotationTool.getShape())) {
          this.annotationTool.getShape().forEach((shape) => shape.dispose());
        } else {
          this.annotationTool.getShape().dispose();
        }
        this.annotationTool.editNode(null);
      }
    },

    updateAllStyles() {
      if (this.annotationTool && this.annotationTool.getShape()) {
        const shape = this.annotationTool.getShape();

        // 创建完整的字体字符串
        const fontString = `${this.textStyle.bold ? 'bold ' : ''}${this.textStyle.italic ? 'italic ' : ''}${this.textStyle.size}px ${this.textStyle.font}`;

        // 创建基本文本样式
        const textStyle = new TextStyle({
          'font': fontString,
          'color': this.textStyle.color,
          'alignment': this.textStyle.align
        });

        // 创建线条样式
        const lineStyle = new LineStyle({
          'color': this.lineStyle.color,
          'width': this.lineStyle.width,
          'pattern': this.getProcessedLinePattern(this.lineStyle.pattern)
        });

        // 创建填充样式
        const fillStyle = new FillStyle(
          this.fillStyle.color,
          this.fillPatterns[this.fillStyle.pattern]
        );

        // 设置形状的所有属性
        const shapeProperties = {
          'textstyle': textStyle,
          'linestyle': lineStyle,
          'fillstyle': fillStyle,
          'sizemode': this.textStyle.fixedFont ?
            (SizeMode.FixedWidth | SizeMode.FixedHeight) :
            SizeMode.WrappedWidth,
          'textbox': {
            'border': this.textStyle.borderRadius > 0,
            'borderradius': this.textStyle.borderRadius,
            'padding': this.textStyle.borderRadius > 0 ? this.textStyle.borderRadius : 5
          }
        };

        // 在形状上设置所有属性
        shape.setProperties(shapeProperties);

        // 在工具上设置属性
        this.annotationTool.setProperties({
          'textbox': shapeProperties.textbox,
          'sizemode': shapeProperties.sizemode
        });

        // 打印更新后的样式数据
        // console.log('样式更新:', {
        //   type: shape.getType ? shape.getType() : '未知类型',
        //   text: shape.getText ? shape.getText() : null,
        //   properties: shape.getProperties(),
        //   textStyle: {
        //     font: fontString,
        //     color: this.textStyle.color,
        //     size: this.textStyle.size,
        //     alignment: this.textStyle.align,
        //     bold: this.textStyle.bold,
        //     italic: this.textStyle.italic
        //   },
        //   lineStyle: {
        //     color: this.lineStyle.color,
        //     width: this.lineStyle.width,
        //     pattern: this.lineStyle.pattern
        //   },
        //   fillStyle: {
        //     color: this.fillStyle.color,
        //     pattern: this.fillStyle.pattern
        //   }
        // });

        // 强制重绘
        if (shape.invalidate) {
          shape.invalidate();
        }
      }
    },

    // 修改字体大小变化处理方法
    handleFontSizeChange(value) {
      this.textStyle.size = value;
      this.updateAllStyles();

      // 更新所有已绘制的文本
      if (this.annotations) {
        const children = this.annotations.getChildren();
        if (children) {
          children.forEach(shape => {
            if (shape.getText) {
              const fontString = `${this.textStyle.bold ? 'bold ' : ''}${this.textStyle.italic ? 'italic ' : ''}${value}px ${this.textStyle.font}`;
              const textStyle = new TextStyle({
                font: fontString,
                color: this.textStyle.color,
                alignment: this.textStyle.align
              });

              shape.setProperties({
                'textstyle': textStyle
              });

              // 打印更新的文本数据
              // console.log('更新已存在的文本:', {
              //   text: shape.getText(),
              //   properties: shape.getProperties(),
              //   textStyle: {
              //     font: fontString,
              //     size: value,
              //     color: this.textStyle.color,
              //     alignment: this.textStyle.align
              //   }
              // });
              try {
                const props = typeof node.getProperties === 'function' ? node.getProperties() : {};
                this.collectedAnnotations.push({ type: 'text', text, properties: props });
                console.log('[collect][text][End] cached count:', this.collectedAnnotations.length, 'last:', this.collectedAnnotations[this.collectedAnnotations.length - 1]);
              } catch (e) { }
            }
          });
        }
        this.requestRepaint();
      }
    },

    // 修改字体变化处理方法
    handleFontChange(value) {
      this.textStyle.font = value;
      this.updateAllStyles();

      // 更新所有已绘制的文本
      if (this.annotations) {
        const children = this.annotations.getChildren();
        if (children) {
          children.forEach(shape => {
            if (shape.getText) {
              const fontString = `${this.textStyle.bold ? 'bold ' : ''}${this.textStyle.italic ? 'italic ' : ''}${this.textStyle.size}px ${value}`;
              const textStyle = new TextStyle({
                font: fontString,
                color: this.textStyle.color,
                alignment: this.textStyle.align
              });

              shape.setProperties({
                'textstyle': textStyle
              });

              // 打印更新的文本数据
              // console.log('更新已存在的文本:', {
              //   text: shape.getText(),
              //   properties: shape.getProperties(),
              //   textStyle: {
              //     font: fontString,
              //     color: this.textStyle.color,
              //     alignment: this.textStyle.align
              //   }
              // });
            }
          });
        }
        this.requestRepaint();
      }
    },

    // 修改字体样式处理方法
    handleFontStyleChange() {
      this.updateAllStyles();
    },

    updateTextStyle() {
      this.updateAllStyles();
    },

    updateLineStyle() {
      // 创建新的线条样式
      const lineStyle = new LineStyle({
        color: this.lineStyle.color,
        width: this.lineStyle.width,
        pattern: this.getProcessedLinePattern(this.lineStyle.pattern)
      });

      // 如果pencilTool正在使用，更新其属性
      if (this.pencilTool && this.pencilTool.isEnabled()) {
        this.pencilTool.setProperties({
          'node': {
            'linestyle': lineStyle
          }
        });

        // 如果有选中的形状，也更新它的样式
        if (this.selectedShape) {
          this.selectedShape.setProperties({
            'linestyle': lineStyle
          });

          // 打印更新后的线条样式数据
          // console.log('线条样式更新:', {
          //   type: this.selectedShape.getType ? this.selectedShape.getType() : '未知类型',
          //   properties: this.selectedShape.getProperties(),
          //   lineStyle: {
          //     color: this.lineStyle.color,
          //     width: this.lineStyle.width,
          //     pattern: this.lineStyle.pattern
          //   }
          // });

          this.requestRepaint();
        }
      }

      // 更新所有已绘制的线条
      if (this.annotations) {
        const children = this.annotations.getChildren();
        if (children) {
          children.forEach(shape => {
            if (shape instanceof Path) {
              shape.setProperties({
                'linestyle': lineStyle
              });

              // 打印每个更新的线条数据
              // console.log('更新已存在的线条:', {
              //   type: shape.getType ? shape.getType() : '未知类型',
              //   properties: shape.getProperties(),
              //   lineStyle: {
              //     color: this.lineStyle.color,
              //     width: this.lineStyle.width,
              //     pattern: this.lineStyle.pattern
              //   }
              // });
            }
          });
        }
        this.requestRepaint();
      }
    },

    updateFillStyle() {
      this.updateAllStyles();
    },

    getFillPatternStyle(key) {
      // 基本样式对象
      const baseStyle = {
        height: '24px',
        width: '100%',
        marginTop: '5px',
        marginBottom: '5px',
        border: '1px solid #ddd',
        background: 'white' // 设置白色背景以便更好显示样式
      };

      // 如果是Solid模式，直接使用设置的颜色
      if (key === 'Solid') {
        return {
          ...baseStyle,
          background: this.fillStyle.color
        };
      }

      // 如果是None，显示透明背景
      if (key === 'None') {
        return {
          ...baseStyle,
          background: 'transparent'
        };
      }

      // 使用FILL_PATTERNS中的URL作为背景
      if (this.FILL_PATTERNS && this.FILL_PATTERNS[key]) {
        return {
          ...baseStyle,
          backgroundImage: `url(${this.FILL_PATTERNS[key]})`,
          backgroundRepeat: 'repeat',
          backgroundSize: 'auto'
        };
      }

      // 默认返回基本样式
      return baseStyle;
    },

    getLinePatternStyle(key) {
      let dashStyle = '';

      // 使用处理后的线条模式
      const patternArray = this.getProcessedLinePattern(key);
      if (patternArray && patternArray.length > 0) {
        dashStyle = patternArray.join('px ') + 'px';
      }

      return {
        background: 'transparent',
        backgroundImage: `url(${this.LINE_PATTERNS[key]})`,
        backgroundRepeat: 'no-repeat',
        backgroundSize: 'contain',
        backgroundPosition: 'center',
        height: '20px',
        width: '100%',
        margin: '5px 0'
      };
    },

    getProcessedLinePattern(pattern) {
      // 如果pattern是数组，直接返回
      if (Array.isArray(pattern)) {
        return pattern;
      }

      // 如果pattern是LINESTYLE_PATTERNS的键，使用该值
      if (this.linePatterns && this.linePatterns[pattern]) {
        return this.linePatterns[pattern];
      }

      // 根据常见的模式名称提供默认数组
      if (typeof pattern === 'string') {
        switch (pattern) {
          case 'Dash':
            return [20, 4];
          case 'Dot':
            return [2, 4];
          case 'DashDot':
            return [20, 4, 2, 4];
          case 'DashDotDot':
            return [20, 4, 2, 4, 2, 4];
          case 'ShortDash':
            return [10, 4];
          case 'LongDash':
            return [40, 4];
          case 'DashLongDash':
            return [20, 4, 40, 4];
          case 'Solid':
          case 'None':
          default:
            return []; // 默认为实线
        }
      }

      // 默认返回空数组（实线）
      //console.log('使用默认实线模式，无法识别模式:', pattern);
      return [];
    },

    debounce(fn, delay = 300) {
      let timer = null;
      return (...args) => {
        if (timer) clearTimeout(timer);
        timer = setTimeout(() => {
          fn.apply(this, args);
        }, delay);
      };
    },

    checkWidgetStatus() {
      if (!this._seismicWidget) {
        console.warn('Widget未初始化');
        this.loadingError = 'Widget未初始化';
        return false;
      }

      // 检查widget的关键方法是否可用
      const requiredMethods = ['setPipeline', 'fitToBounds', 'getOverlayLayer', 'getManipulatorLayer', 'getTool', 'invalidate'];
      for (const method of requiredMethods) {
        if (typeof this._seismicWidget[method] !== 'function') {
          console.error(`Widget缺少关键方法: ${method}`);
          this.loadingError = `Widget初始化不完整，缺少方法: ${method}`;
          return false;
        }
      }

      try {
        // 验证freezeupdate设置是否正常工作
        this._seismicWidget.setOptions({ 'freezeupdate': false });
      } catch (error) {
        console.error('设置widget选项失败:', error);
        this.loadingError = `Widget选项设置失败: ${error.message}`;
        return false;
      }

      return true;
    },

    // 修改边框圆角更新方法
    handleBorderRadiusChange(value) {
      // 确保值为数字
      const radius = parseInt(value) || 0;
      this.textStyle.borderRadius = radius;
      this.updateAllStyles();
    },

    // 修改固定字体更新方法
    handleFixedFontChange(value) {
      this.textStyle.fixedFont = value;
      this.updateAllStyles();
    },

    // 添加清除所有工具状态的方法
    clearAllTools() {
      this.showTextStylePanel = false;
      this.showLineStylePanel = false;
      this.isDrawingText = false;

      if (this.annotationTool) {
        this.annotationTool.setEnabled(false);
        this.annotationTool.editNode(null);
      }

      if (this.pencilTool) {
        this.pencilTool.setEnabled(false);
        // 修复：如果 plots 为 null，直接使用 _seismicWidget
        const widget = (this.plots && this.plots.getRoot) ? this.plots.getRoot() : this._seismicWidget;
        if (widget && widget.getTool()) {
          widget.getTool().remove(this.pencilTool);
        }
      }

      this.requestRepaint();
    },

    // 修改请求重绘的方法
    requestRepaint() {
      // 只调用有invalidate方法的对象
      if (this._seismicWidget) {
        this._seismicWidget.invalidate();
      }
      if (this.annotations) {
        this.annotations.invalidate();
      }
      const widget = (this.plots && this.plots.getRoot) ? this.plots.getRoot() : this._seismicWidget;
      if (widget) {
        widget.invalidate();
      }
    },

    // 添加更新选择视觉反馈的方法
    updateSelectionVisualFeedback() {
      // 更新所有形状的选中状态
      if (this.annotationLayer) {
        const children = this.annotationLayer.getChildren();
        if (children) {
          children.forEach(shape => {
            const isSelected = this.selectedShapes.indexOf(shape) >= 0;
            shape.setProperties({
              'selected': isSelected
            });
          });
        }
      }
      this.requestRepaint();
    },

    // 添加切换颜色映射的方法
    switchColorMap(colorMapName) {
      if (!this.pipeline || !this.colorProvider) {
        console.error('Pipeline or colorProvider not initialized');
        return;
      }

      this.currentColorMap = colorMapName;

      try {
        // 创建新的颜色映射
        const colorMap = this.colorProvider.createNamedColorMap(colorMapName, 256);
        if (!colorMap) {
          console.error(`创建颜色映射失败: ${colorMapName}可能未正确注册`);
          return;
        }

        // 设置两个pipeline的颜色映射
        this.pipeline.setColorMap(colorMap);
        if (this.pipelineBottom) this.pipelineBottom.setColorMap(colorMap);

        // 更新widget的颜色映射
        if (this._seismicWidget) {
          this._seismicWidget.setOptions({
            'colors': {
              'colorMap': colorMap
            }
          });

          // 强制重绘
          this._seismicWidget.invalidate();
          this._seismicWidget.fitToBounds();
        }

        if (this._seismicWidgetBottom) {
          this._seismicWidgetBottom.setOptions({ 'colors': { 'colorMap': colorMap } });
          this._seismicWidgetBottom.invalidate();
          this._seismicWidgetBottom.fitToBounds();
        }

        // 如果plots对象存在redraw方法，使用它来触发重绘
        if (this.plots && typeof this.plots.redraw === 'function') {
          this.plots.redraw();
        }

        //console.log(`成功切换到颜色映射: ${colorMapName}`);
      } catch (error) {
        console.error(`切换颜色映射失败: ${error.message}`);
      }
    },

    // 添加注册颜色映射的方法
    registerColorMaps(colorProvider) {
      if (!colorProvider) {
        console.error('colorProvider为空，无法注册颜色映射');
        return;
      }

      try {
        // 注册黑白渐变色映射（与seismicplot一致）
        colorProvider.register('WhiteBlack', (map) => {
          if (!map) {
            console.error('WhiteBlack映射对象为空');
            return;
          }

          const colors = new Array(256);

          try {
            // 白色到黑色的渐变
            interpolate(colors, 0, 255, {
              A: 255,
              R: 255,
              G: 255,
              B: 255
            }, {
              A: 255,
              R: 0,
              G: 0,
              B: 0
            });

            map.set(colors);
          } catch (error) {
            console.error('设置WhiteBlack颜色映射失败:', error);
          }
        });

        // 注册灰度渐变色映射
        colorProvider.register('CustomGrayScale', (map) => {
          if (!map) {
            console.error('CustomGrayScale映射对象为空');
            return;
          }

          const colors = new Array(256);

          try {
            // -4000到181范围保持纯白色
            interpolate(colors, 0, 110, {
              A: 255,
              R: 255,
              G: 255,
              B: 255
            }, {
              A: 255,
              R: 255,
              G: 255,
              B: 255
            });

            // 181开始，从(253,253,253)开始到566
            interpolate(colors, 111, 120, {
              A: 255,
              R: 253,
              G: 253,
              B: 253
            }, {
              A: 255,
              R: 240,
              G: 240,
              B: 240
            });

            // 566开始，颜色开始变深
            interpolate(colors, 121, 160, {
              A: 255,
              R: 240,
              G: 240,
              B: 240
            }, {
              A: 255,
              R: 180,
              G: 180,
              B: 180
            });

            // 继续渐变到深色
            interpolate(colors, 161, 255, {
              A: 255,
              R: 180,
              G: 180,
              B: 180
            }, {
              A: 255,
              R: 6,
              G: 6,
              B: 6
            });

            map.set(colors);
          } catch (error) {
            console.error('设置CustomGrayScale颜色映射失败:', error);
          }
        });

        // 注册新的红色系列渐变映射
        colorProvider.register('CustomRedScale', (map) => {
          if (!map) {
            console.error('CustomRedScale映射对象为空');
            return;
          }

          const colors = new Array(256);

          try {
            // 第1段：起始红色到红棕色 (0-20%)
            interpolate(colors, 0, 40, {
              A: 255,
              R: 246,
              G: 40,
              B: 26
            }, {
              A: 255,
              R: 221,
              G: 139,
              B: 102
            });

            // 第2段：红棕色到浅褐色 (20-40%)
            interpolate(colors, 41, 84, {
              A: 255,
              R: 221,
              G: 139,
              B: 102
            }, {
              A: 255,
              R: 215,
              G: 198,
              B: 146
            });

            // 第3段：浅褐色到白色 (40-60%)
            interpolate(colors, 85, 126, {
              A: 255,
              R: 215,
              G: 198,
              B: 146
            }, {
              A: 255,
              R: 251,
              G: 250,
              B: 255
            });

            // 第4段：白色到灰紫色 (60-75%)
            interpolate(colors, 127, 168, {
              A: 255,
              R: 251,
              G: 250,
              B: 255
            }, {
              A: 255,
              R: 110,
              G: 110,
              B: 138
            });

            // 第5段：灰紫色到深灰 (75-90%)
            interpolate(colors, 169, 210, {
              A: 255,
              R: 110,
              G: 110,
              B: 138
            }, {
              A: 255,
              R: 50,
              G: 49,
              B: 54
            });

            // 第6段：保持深灰到结束 (90-100%)
            interpolate(colors, 211, 255, {
              A: 255,
              R: 50,
              G: 49,
              B: 54
            }, {
              A: 255,
              R: 50,
              G: 49,
              B: 54
            });

            map.set(colors);
          } catch (error) {
            console.error('设置CustomRedScale颜色映射失败:', error);
          }
        });

        // 注册多段颜色渐变
        colorProvider.register('BlueWhiteRed', (map) => {
          if (!map) {
            console.error('BlueWhiteRed映射对象为空');
            return;
          }

          const colors = new Array(256);

          try {
            // 第一段：253, 27, 21 到 255, 205, 203 (0-63)
            interpolate(colors, 0, 63, {
              A: 255,
              R: 254,
              G: 13,
              B: 6
            }, {
              A: 255,
              R: 255,
              G: 205,
              B: 203
            });

            // 第二段：255, 205, 203 到 255, 251, 251 (64-127)
            interpolate(colors, 64, 127, {
              A: 255,
              R: 255,
              G: 205,
              B: 203
            }, {
              A: 255,
              R: 255,
              G: 251,
              B: 251
            });

            // 第三段：255, 251, 251 到 206, 207, 255 (128-191)
            interpolate(colors, 128, 191, {
              A: 255,
              R: 255,
              G: 251,
              B: 251
            }, {
              A: 255,
              R: 206,
              G: 207,
              B: 255
            });

            // 第四段：206, 207, 255 到 30, 38, 253 (192-255)
            interpolate(colors, 192, 255, {
              A: 255,
              R: 206,
              G: 207,
              B: 255
            }, {
              A: 255,
              R: 9,
              G: 25,
              B: 254
            });

            map.set(colors);
          } catch (error) {
            console.error('设置BlueWhiteRed颜色映射失败:', error);
          }
        });


        //console.log('颜色映射注册成功');
      } catch (error) {
        console.error('注册颜色映射失败:', error);
      }
    },

    async toggleLineStylePanel() {
      // 如果工具已经激活，则停用
      if (this.showLineStylePanel) {
        this.deactivatePencilTool();
        return;
      }

      this.clearAllTools();
      this.showLineStylePanel = true;

      if (!this.checkWidgetStatus() || !this.isWidgetReady) return;

      // 修复：如果 plots 为 null，直接使用 _seismicWidget
      const widget = (this.plots && this.plots.getRoot) ? this.plots.getRoot() : this._seismicWidget;
      if (!widget) return;

      // 确保注释层存在
      if (!this.annotations) {
        this.annotations = new Group();
        widget.getOverlayLayer().addChild(this.annotations);
        this.annotations.setVisible(true);
      }

      // 创建或更新铅笔工具
      if (!this.pencilTool) {
        const lineStyle = new LineStyle({
          color: this.lineStyle.color,
          width: this.lineStyle.width,
          pattern: this.getProcessedLinePattern(this.lineStyle.pattern)
        });

        const pencilProperties = {
          'layer': widget.getManipulatorLayer(),
          'mode': PaintMode.Pencil,
          'editmode': EditMode.Create,
          'node': {
            'linestyle': lineStyle,
            'selectable': true,
            'movable': true,
            'editable': true
          }
        };

        //console.log('线条绘制工具配置:', pencilProperties);
        this.pencilTool = new Paint(pencilProperties);

        // 添加事件监听
        this.pencilTool
          .addListener(EditEvents.Start, (tool, command) => {
            const node = command.getNode();
            // console.log('开始绘制线条:', {
            //   tool: tool.getMode(),
            //   properties: node.getProperties()
            // });
            this.annotations.addChild(node);
          })
          .addListener(EditEvents.Change, (tool, event) => {
            const node = tool.getShape();
            if (node) {
              // console.log('线条绘制更新:', {
              //   properties: node.getProperties(),
              //   bounds: node.getBounds ? node.getBounds() : null
              // });
            }
          })
          .addListener(EditEvents.End, (tool, node) => {
            if (node) {
              const props = typeof node.getProperties === 'function' ? node.getProperties() : {};
              console.log('[pencilTool][End] 绘制线条节点', {
                node,
                properties: props
              });
              try {
                this.collectedAnnotations.push({ type: 'path', properties: props, panel: 'top', _nodeRef: node });
                console.log('[collect][path][End] cached count:', this.collectedAnnotations.length, 'last:', this.collectedAnnotations[this.collectedAnnotations.length - 1]);
              } catch (e) { }
            }
            if (node && this.annotations.indexOfChild(node) === -1) {
              this.annotations.addChild(node);
            }

            // 关键修复：绘制完成后，确保节点保持可编辑属性
            try {
              const props = typeof node.getProperties === 'function' ? node.getProperties() : {};
              if (!props.selectable || !props.movable || !props.editable) {
                // 如果属性丢失，重新设置
                const currentLineStyle = props.linestyle || new LineStyle({
                  color: this.lineStyle?.color || '#0351ad',
                  width: this.lineStyle?.width || 2,
                  pattern: this.getProcessedLinePattern ? this.getProcessedLinePattern(this.lineStyle?.pattern) : []
                });
                node.setProperties({
                  ...props,
                  linestyle: currentLineStyle,
                  selectable: true,
                  movable: true,
                  editable: true
                });
              }
            } catch (e) {
              console.warn('设置线条节点编辑属性失败:', e);
            }

            // 修复：绘制完成后，保持编辑模式，让用户可以立即编辑刚绘制的线条
            // 用户可以通过点击空白区域或按 ESC 来取消编辑，然后继续绘制新线条
            try {
              if (this.pencilTool && this.pencilTool.isEnabled() && this.showLineStylePanel) {
                // 设置编辑模式，让用户可以选择和编辑刚绘制的线条
                this.pencilTool.setEditMode(EditMode.EditNode);
                this.pencilTool.editNode(node);
                this.selectedShape = node;
              }
            } catch (e) {
              console.warn('设置线条编辑模式失败:', e);
            }

            this.requestRepaint();
          });
      }

      // 设置工具为活动状态
      this.pencilTool.setMode(PaintMode.Pencil);
      this.pencilTool.setEditMode(EditMode.Create);

      // 获取工具管理器并添加工具
      const toolManager = widget.getTool();

      try {
        toolManager.remove(this.pencilTool);
      } catch (e) {
        // 忽略错误，工具可能已经被移除
      }

      toolManager.insert(0, this.pencilTool);
      this.pencilTool.setEnabled(true);

      // 同步启用底部线条工具
      if (this.pencilToolBottom && this._seismicWidgetBottom) {
        try {
          const tm = this._seismicWidgetBottom.getTool && this._seismicWidgetBottom.getTool();
          if (tm) {
            // 暂时冻结 widget 更新，避免刷新导致闪烁
            try {
              if (this._seismicWidgetBottom.setOptions) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': true });
              }
            } catch (e) { }

            // 关键修复：先禁用并移除文本工具，避免工具冲突
            if (this.annotationToolBottom) {
              try {
                this.annotationToolBottom.setEnabled(false);
                this.annotationToolBottom.editNode(null);
                tm.remove(this.annotationToolBottom);
              } catch (e) { }
            }
            // 移除并重新插入线条工具，确保它在最前面
            try { tm.remove(this.pencilToolBottom); } catch (e) { }
            tm.insert(0, this.pencilToolBottom);
            // 确保线条工具设置为创建模式
            this.pencilToolBottom.setMode(PaintMode.Pencil);
            this.pencilToolBottom.setEditMode(EditMode.Create);
            this.pencilToolBottom.setEnabled(true);

            // 恢复 widget 更新
            try {
              if (this._seismicWidgetBottom.setOptions) {
                this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
              }
            } catch (e) { }
          }
        } catch (e) {
          // 确保即使出错也恢复更新
          try {
            if (this._seismicWidgetBottom && this._seismicWidgetBottom.setOptions) {
              this._seismicWidgetBottom.setOptions({ 'freezeupdate': false });
            }
          } catch (e2) { }
        }
      }
    },

    deactivatePencilTool() {
      this.showLineStylePanel = false;
      if (this.pencilTool) {
        this.pencilTool.setEnabled(false);
        // 修复：如果 plots 为 null，直接使用 _seismicWidget
        const widget = (this.plots && this.plots.getRoot) ? this.plots.getRoot() : this._seismicWidget;
        if (widget && widget.getTool()) {
          try {
            widget.getTool().remove(this.pencilTool);
          } catch (e) {
            // 忽略错误，工具可能已经被移除
          }
        }

        // 清除选中的形状
        this.selectedShape = null;
      }
    },

    zoomIn() {
      this.zoomScale = Math.min(this.zoomScale * 1.2, 6);
    },

    zoomOut() {
      this.zoomScale = Math.max(this.zoomScale / 1.2, 0.2);
    },

    async exportToPDF(data) {
      if (!this.plots || !this.isWidgetReady) {
        this.$message.warning('请等待数据加载完成');
        return;
      }

      try {
        // 处理PDF导出逻辑...
        this.$message.success('PDF导出成功');
      } catch (error) {
        console.error('导出PDF时发生错误:', error);
        this.$message.error('导出PDF失败: ' + error.message);
      } finally {
        // 确保无论导出成功还是失败，都关闭弹窗
        this.showPrintDialog = false;
      }
    },

    /**
     * 绑定右键菜单事件监听器
     */
    bindContextMenuListeners() {
      // 先移除旧的监听器（如果存在）
      if (this.$refs.plot) {
        this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
      }
      if (this.$refs.plot2) {
        this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
      }

      // 添加新的监听器
      if (this.$refs.plot) {
        this.$refs.plot.addEventListener('contextmenu', this.showContextMenu);
      }
      if (this.$refs.plot2) {
        this.$refs.plot2.addEventListener('contextmenu', this.showContextMenu);
        // 移除 mouseenter/mouseleave 事件监听器，避免频繁刷新导致闪烁
        // 这些监听器会在鼠标移入/移出时触发刷新，导致图闪烁
        // 在点击底部画布时强校验绑定的数据是否为当前索引
        // 移除 mousedown 事件监听器，避免每次点击都触发刷新导致闪烁
        // 在切换下一道时已经在 loadCurrentSegy 中调用了 assertBottomPipelineCurrent
        // 不需要在每次点击时都检查
      }
      // document 的 click 事件只需要绑定一次
      if (!this._contextMenuClickBound) {
        document.addEventListener('click', this.hideContextMenu);
        this._contextMenuClickBound = true;
      }
    },

    /**
     * 显示右键菜单
     */
    showContextMenu(event) {
      event.preventDefault();

      // 获取当前活动的工具
      const activeTool = this.pencilTool && this.pencilTool.isEnabled() ? this.pencilTool :
        (this.annotationTool && this.annotationTool.isEnabled() ? this.annotationTool : null);

      // 如果没有活动工具，则不显示菜单
      if (!activeTool) {
        //console.log('No active tool');
        return;
      }

      // 获取画布相对于视口的位置（根据事件目标判断是哪个画布）
      const targetCanvas = event.target === this.$refs.plot2 ? this.$refs.plot2 : this.$refs.plot;
      const rect = targetCanvas ? targetCanvas.getBoundingClientRect() : this.$refs.plot.getBoundingClientRect();

      // 计算相对于画布的坐标
      this.contextMenu.x = event.clientX - rect.left;
      this.contextMenu.y = event.clientY - rect.top;
      this.contextMenu.visible = true;

      // 记录当前右键菜单使用的工具（即使没有选中形状，也记录工具，以便菜单项可以检查状态）
      this._contextMenuTool = activeTool;

      // //console.log('Context menu shown:', {
      //   x: this.contextMenu.x,
      //   y: this.contextMenu.y,
      //   tool: activeTool.getMode(),
      //   shape: activeTool.getShape() ? activeTool.getShape().getType() : null
      // });

      event.stopPropagation();
    },

    /**
     * 隐藏右键菜单
     */
    hideContextMenu() {
      if (this.contextMenu.visible) {
        this.contextMenu.visible = false;
        this._contextMenuTool = null;
        //console.log('Context menu hidden');
      }
    },

    /**
     * 检查菜单项是否可用
     */
    isMenuItemEnabled(action) {
      // 获取当前活动的工具
      const tool = this._contextMenuTool;

      if (!tool) return false;

      switch (action) {
        case 'undo':
          // 使用工具的getHistory方法获取历史记录对象
          return tool.getHistory && tool.getHistory() && tool.getHistory().canUndo();
        case 'redo':
          // 使用工具的getHistory方法获取历史记录对象
          return tool.getHistory && tool.getHistory() && tool.getHistory().canRedo();
        case 'copy':
        case 'delete':
          return tool.getShape() != null;
        case 'paste':
          return this.clipboard !== null;
        default:
          return true;
      }
    },
    /**
     * 处理菜单动作
     */
    handleMenuAction(action) {
      if (!this.isMenuItemEnabled(action)) return;

      const tool = this._contextMenuTool;

      if (!tool) {
        this.hideContextMenu();
        return;
      }

      switch (action) {
        case 'undo':
          // 使用工具的undo方法或history对象的undo方法
          if (tool.undo) {
            tool.undo();
          } else if (tool.getHistory && tool.getHistory()) {
            tool.getHistory().undo();
          }
          break;
        case 'redo':
          // 使用工具的redo方法或history对象的redo方法
          if (tool.redo) {
            tool.redo();
          } else if (tool.getHistory && tool.getHistory()) {
            tool.getHistory().redo();
          }
          break;
        case 'copy':
          this.copyShape(tool);
          break;
        case 'paste':
          this.pasteShape();
          break;
        case 'delete':
          this.deleteShape(tool);
          break;
      }

      this.hideContextMenu();
      this.requestRepaint();
    },

    copyShape(tool) {
      const shape = tool.getShape();
      if (!shape) return;

      // 存储形状的克隆
      this.clipboard = Array.isArray(shape) ?
        shape.map(node => node.clone()) :
        [shape.clone()];
    },

    pasteShape() {
      if (!this.clipboard || this.clipboard.length === 0) return;

      // 创建偏移量，以便粘贴的形状不会完全覆盖原始形状
      const offset = 20;

      // 克隆并移动复制的形状
      this.clipboard.forEach(node => {
        const clone = node.clone();

        // 移动克隆的形状
        if (clone.translate) {
          clone.translate(offset, offset);
        }

        // 添加到注释层
        this.annotations.addChild(clone);
      });

      this.requestRepaint();
    },

    deleteShape(tool) {
      const shape = tool.getShape();
      if (!shape) return;

      // 如果是数组，删除所有选中的形状
      if (Array.isArray(shape)) {
        shape.forEach(node => {
          const index = this.annotations.indexOfChild(node);
          if (index >= 0) {
            this.annotations.removeChild(node);
          }
        });
      } else {
        // 删除单个形状
        const index = this.annotations.indexOfChild(shape);
        if (index >= 0) {
          this.annotations.removeChild(shape);
        }
      }

      // 清除工具当前编辑的节点
      tool.editNode(null);

      this.requestRepaint();
    },

    handleKeyDown(event) {
      // 检查是否有活动的工具
      const activeTool = this.pencilTool && this.pencilTool.isEnabled() ? this.pencilTool :
        (this.annotationTool && this.annotationTool.isEnabled() ? this.annotationTool : null);

      if (!activeTool) return;

      // 获取历史记录对象
      const history = activeTool.getHistory && activeTool.getHistory();

      // Ctrl+Z: 撤销
      if (event.ctrlKey && event.key === 'z') {
        if (activeTool.undo) {
          activeTool.undo();
          this.requestRepaint();
          event.preventDefault();
        } else if (history && history.canUndo && history.canUndo()) {
          history.undo();
          this.requestRepaint();
          event.preventDefault();
        }
      }

      // Ctrl+Y: 重做
      else if (event.ctrlKey && event.key === 'y') {
        if (activeTool.redo) {
          activeTool.redo();
          this.requestRepaint();
          event.preventDefault();
        } else if (history && history.canRedo && history.canRedo()) {
          history.redo();
          this.requestRepaint();
          event.preventDefault();
        }
      }

      // Delete: 删除
      else if (event.key === 'Delete') {
        if (activeTool.getShape()) {
          this.deleteShape(activeTool);
          event.preventDefault();
        }
      }
    },

    // 添加一个新方法，用于切换形状的编辑状态
    toggleShapeEditMode(shape) {
      if (!shape) return;

      // 获取活动工具
      const activeTool = this.pencilTool && this.pencilTool.isEnabled() ? this.pencilTool :
        (this.annotationTool && this.annotationTool.isEnabled() ? this.annotationTool : null);

      if (!activeTool) return;

      // 如果当前不是编辑模式，则切换到编辑模式
      if (activeTool.getMode() !== PaintMode.Edit) {
        activeTool.setMode(PaintMode.Edit);
      }

      // 如果当前编辑的不是这个形状，则开始编辑这个形状
      if (activeTool.getShape() !== shape) {
        activeTool.setEditMode(EditMode.EditNode);
        activeTool.editNode(shape);
        this.selectedShape = shape;
      }

      this.requestRepaint();
    },

    getElementIcon(mdiIcon) {
      // 将Vuetify的mdi图标转换为Element UI图标
      const iconMap = {
        'mdi-undo': 'el-icon-refresh-left',
        'mdi-redo': 'el-icon-refresh-right',
        'mdi-content-copy': 'el-icon-document-copy',
        'mdi-content-paste': 'el-icon-document-add',
        'mdi-delete': 'el-icon-delete'
      };

      return iconMap[mdiIcon] || 'el-icon-warning';
    },

    // 添加鼠标悬停相关事件
    initCursorTools() {
      // 实现鼠标悬停相关事件的初始化逻辑
    },

    // 添加鼠标移动处理方法
    handleMouseMove(event) {
      if (!this._seismicWidget || !this.isHovering) return;

      // 使用内置状态栏，不需要额外的处理逻辑
    },

    // 添加保存标注数据的方法
    saveAnnotation(node) {
      if (!node) {
        console.warn('无法保存标注：节点为空');
        return;
      }

      try {
        // 获取文本样式
        const textStyle = node.getTextStyle ? node.getTextStyle() : null;
        let fontSize = 22; // 默认字体大小

        // 从字体字符串中提取字体大小
        if (textStyle && textStyle.getFont) {
          const fontString = textStyle.getFont();
          const fontSizeMatch = fontString.match(/(\d+)px/);
          if (fontSizeMatch) {
            fontSize = parseInt(fontSizeMatch[1], 10);
          }
        }

        // 构建标注数据
        const annotationData = {
          type: node.getType ? node.getType() : 'text',
          text: node.getText ? node.getText() : '',
          properties: node.getProperties(),
          position: {
            x: node.getProperties().ax,
            y: node.getProperties().ay
          },
          styles: {
            textStyle: {
              font: textStyle ? textStyle.getFont() : '',
              color: textStyle ? textStyle.getColor() : '#000000',
              size: fontSize,
              alignment: textStyle ? textStyle.getAlignment() : 'left',
              bold: textStyle ? Boolean(textStyle.getFont().includes('bold')) : false,
              italic: textStyle ? Boolean(textStyle.getFont().includes('italic')) : false
            },
            lineStyle: {
              color: node.getLineStyle ? node.getLineStyle().getColor() : '#000000',
              width: node.getLineStyle ? node.getLineStyle().getWidth() : 1,
              pattern: node.getLineStyle ? node.getLineStyle().getPattern() : []
            },
            fillStyle: {
              color: node.getFillStyle ? node.getFillStyle().getColor() : 'transparent',
              pattern: node.getFillStyle ? node.getFillStyle().getPattern() : 'Solid'
            }
          }
        };

        // 验证数据
        const validation = {
          isValid: Boolean(node && node.getText),
          hasRequiredProperties: Boolean(
            node.getProperties().ax !== undefined &&
            node.getProperties().ay !== undefined
          ),
          hasStyles: Boolean(textStyle && node.getLineStyle && node.getFillStyle)
        };

        //console.log('标注数据验证:', validation);

        if (Object.values(validation).every(v => v)) {
          this.savedAnnotations.push(annotationData);
          // console.log('标注数据已保存:', {
          //   data: annotationData,
          //   totalAnnotations: this.savedAnnotations.length
          // });
        } else {
          console.warn('标注数据验证失败:', validation);
        }
      } catch (error) {
        console.error('保存标注数据时出错:', {
          error: error.message,
          stack: error.stack,
          node: node ? {
            type: node.getType ? node.getType() : 'unknown',
            properties: node.getProperties ? node.getProperties() : null
          } : null
        });
      }
    },

    // 添加恢复标注数据的方法
    restoreAnnotations() {
      // 先恢复文本标注
      if (!this.annotations || !this._seismicWidget || !this.savedAnnotations) {
        console.warn('无法恢复标注：缺少必要组件', {
          hasAnnotations: Boolean(this.annotations),
          hasWidget: Boolean(this._seismicWidget),
          hasSavedData: Boolean(this.savedAnnotations),
          savedAnnotationsCount: this.savedAnnotations ? this.savedAnnotations.length : 0
        });
        return;
      }

      try {
        console.log('[restoreAnnotations] 开始恢复文本标注，savedAnnotations 数量:', this.savedAnnotations.length);
        console.log('[restoreAnnotations] savedAnnotations 完整数据:', JSON.stringify(this.savedAnnotations, null, 2));
        console.log('[restoreAnnotations] savedAnnotations 对象:', this.savedAnnotations);

        // 恢复文本标注
        this.savedAnnotations.forEach((data, index) => {
          try {
            const textNode = new Text({
              text: data.text || data.properties.text,
              x: data.properties.ax,
              y: data.properties.ay,
              width: data.properties.width || 66,
              height: data.properties.height || 22,
              sizemode: data.properties.sizemode || 5,
              selectable: true,
              movable: true,
              editable: true,
              preserveaspectratio: data.properties.preserveaspectratio || false
            });

            const fullProperties = {
              ...data.properties,
              textstyle: new TextStyle({
                color: data.properties.textstyle.Lx,
                font: data.properties.textstyle.lH,
                alignment: data.properties.textstyle.Vf
              }),
              linestyle: new LineStyle({
                color: data.properties.linestyle.Lx,
                width: data.properties.linestyle.fA,
                pattern: []
              }),
              fillstyle: new FillStyle({
                color: data.properties.fillstyle && data.properties.fillstyle.Lx ? data.properties.fillstyle.Lx : '#c7e1f6'
              })
            };

            textNode.setProperties(fullProperties);
            this.annotations.addChild(textNode);

            //console.log(`恢复文本标注 ${index + 1}/${this.savedAnnotations.length}:`, {
            //   text: data.text || data.properties.text,
            //   position: { x: data.properties.ax, y: data.properties.ay }
            // });
          } catch (error) {
            console.error(`恢复文本标注 ${index + 1} 时出错:`, {
              error: error.message,
              annotationData: data
            });
          }
        });

        // 恢复线条标注
        this.restoreLineAnnotations();

        // 强制重绘
        this.requestRepaint();

        // 调整视图以显示所有标注
        if (this._seismicWidget && typeof this._seismicWidget.fitToBounds === 'function') {
          this._seismicWidget.fitToBounds();
        }
      } catch (error) {
        console.error('恢复标注数据时出错:', {
          error: error.message,
          stack: error.stack
        });
      }
    },

    // 添加恢复线条标注的方法
    restoreLineAnnotations() {
      if (!this.annotations || !this._seismicWidget || !this.savedLineAnnotations) {
        console.warn('无法恢复线条标注：缺少必要组件');
        return;
      }

      try {
        // console.log('开始恢复线条标注:', {
        //   totalLines: this.savedLineAnnotations.length
        // });

        this.savedLineAnnotations.forEach((data, index) => {
          try {
            // 创建路径对象
            const path = new Path();

            // 使用 moveTo 移动到第一个点
            if (data.properties.x.length > 0) {
              path.moveTo(data.properties.x[0], data.properties.y[0]);

              // 使用 lineTo 连接后续的点
              for (let i = 1; i < data.properties.x.length; i++) {
                path.lineTo(data.properties.x[i], data.properties.y[i]);
              }
            }

            // 设置线条样式
            const lineStyle = new LineStyle({
              color: data.properties.linestyle.Lx || '#0351ad',
              width: data.properties.linestyle.fA || 2,
              pattern: []
            });

            // 设置属性
            path.setProperties({
              linestyle: lineStyle,
              selectable: true,
              movable: true,
              editable: true
            });

            // 添加到标注层
            this.annotations.addChild(path);

            // console.log(`恢复线条标注 ${index + 1}/${this.savedLineAnnotations.length}:`, {
            //   points: data.properties.x.length,
            //   style: lineStyle,
            //   bounds: data.bounds
            // });
          } catch (error) {
            console.error(`恢复线条标注 ${index + 1} 时出错:`, {
              error: error.message,
              data: data
            });
          }
        });

        // 强制重绘
        this.requestRepaint();

        // 调整视图以显示所有标注
        if (this._seismicWidget && typeof this._seismicWidget.fitToBounds === 'function') {
          this._seismicWidget.fitToBounds();
        }
      } catch (error) {
        console.error('恢复线条标注时出错:', {
          error: error.message,
          stack: error.stack
        });
      }
    },

    // 底部：恢复文本标注
    restoreAnnotationsBottom() {
      if (!this.annotationsBottom || !this._seismicWidgetBottom || !this.savedAnnotationsBottom) return;
      try {
        this.savedAnnotationsBottom.forEach((data) => {
          const textNode = new Text({
            text: data.text || data.properties.text,
            x: data.properties.ax,
            y: data.properties.ay,
            width: data.properties.width || 66,
            height: data.properties.height || 22,
            sizemode: data.properties.sizemode || 5,
            selectable: true,
            movable: true,
            editable: true,
            preserveaspectratio: data.properties.preserveaspectratio || false
          });
          const fullProps = {
            ...data.properties,
            textstyle: new TextStyle({
              color: data.properties.textstyle.Lx,
              font: data.properties.textstyle.lH,
              alignment: data.properties.textstyle.Vf
            }),
            linestyle: new LineStyle({
              color: data.properties.linestyle.Lx,
              width: data.properties.linestyle.fA,
              pattern: []
            }),
            fillstyle: new FillStyle({
              color: data.properties.fillstyle && data.properties.fillstyle.Lx ? data.properties.fillstyle.Lx : '#c7e1f6'
            })
          };
          textNode.setProperties(fullProps);
          this.annotationsBottom.addChild(textNode);
        });
        this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate();
        if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) this._seismicWidgetBottom.fitToBounds();
      } catch (e) { console.warn('restoreAnnotationsBottom error:', e); }
    },

    // 底部：恢复线条标注
    restoreLineAnnotationsBottom() {
      if (!this.annotationsBottom || !this._seismicWidgetBottom || !this.savedLineAnnotationsBottom) return;
      try {
        this.savedLineAnnotationsBottom.forEach((data) => {
          const path = new Path();
          if (data.properties.x && data.properties.x.length > 0) {
            path.moveTo(data.properties.x[0], data.properties.y[0]);
            for (let i = 1; i < data.properties.x.length; i++) {
              path.lineTo(data.properties.x[i], data.properties.y[i]);
            }
          }
          const lineStyle = new LineStyle({
            color: data.properties.linestyle.Lx || '#0351ad',
            width: data.properties.linestyle.fA || 2,
            pattern: []
          });
          path.setProperties({ linestyle: lineStyle, selectable: true, movable: true, editable: true });
          this.annotationsBottom.addChild(path);
        });
        this._seismicWidgetBottom && this._seismicWidgetBottom.invalidate && this._seismicWidgetBottom.invalidate();
        if (this._seismicWidgetBottom && this._seismicWidgetBottom.fitToBounds) this._seismicWidgetBottom.fitToBounds();
      } catch (e) { console.warn('restoreLineAnnotationsBottom error:', e); }
    },

    // 添加在指定位置创建文本的方法
    createTextAtPosition() {
      if (!this._seismicWidget || !this.annotations) {
        console.warn('Widget or annotations layer not ready');
        return;
      }

      try {
        // 创建文本节点
        const textNode = new Text({
          text: "地震",
          x: 826.370447661679,  // 指定的x坐标
          y: 2.1615720524017465, // 指定的y坐标
          width: 100,
          height: 30,
          sizemode: SizeMode.WrappedWidth,
          selectable: true,
          movable: true,
          editable: true
        });

        // 设置文本样式
        textNode.setProperties({
          'textstyle': new TextStyle({
            color: 'rgba(200, 109, 109, 1)',
            font: 'bold 22px Arial Black',
            alignment: 'left'
          }),
          'linestyle': new LineStyle({
            color: 'rgba(100, 158, 227, 1)',
            width: 3,
            pattern: []
          }),
          'fillstyle': new FillStyle({
            color: 'rgba(30, 70, 102, 1)'
          })
        });

        // 添加到标注层
        this.annotations.addChild(textNode);

        // 强制重绘
        this._seismicWidget.invalidate();

        //console.log('文本标注已创建在指定位置');
      } catch (error) {
        console.error('创建文本标注时出错:', error);
      }
    },

    // 添加新的辅助方法
    detectChanges(previousState, currentNode) {
      if (!previousState || !currentNode) return {};

      const changes = {};
      const currentProps = currentNode.getProperties();

      // 检查属性变化
      if (previousState.properties) {
        changes.properties = {};
        for (const key in currentProps) {
          if (JSON.stringify(previousState.properties[key]) !== JSON.stringify(currentProps[key])) {
            changes.properties[key] = {
              from: previousState.properties[key],
              to: currentProps[key]
            };
          }
        }
      }

      // 检查文本样式变化
      if (previousState.textStyle && currentNode.getTextStyle) {
        const currentTextStyle = currentNode.getTextStyle();
        changes.textStyle = {};

        if (previousState.textStyle.font !== currentTextStyle.getFont()) {
          changes.textStyle.font = {
            from: previousState.textStyle.font,
            to: currentTextStyle.getFont()
          };
        }

        if (previousState.textStyle.color !== currentTextStyle.getColor()) {
          changes.textStyle.color = {
            from: previousState.textStyle.color,
            to: currentTextStyle.getColor()
          };
        }

        if (previousState.textStyle.size !== currentTextStyle.size) {
          changes.textStyle.size = {
            from: previousState.textStyle.size,
            to: currentTextStyle.size
          };
        }

        if (previousState.textStyle.alignment !== currentTextStyle.getAlignment()) {
          changes.textStyle.alignment = {
            from: previousState.textStyle.alignment,
            to: currentTextStyle.getAlignment()
          };
        }
      }

      return changes;
    },

    // 切换内部滚动条同步
    toggleInternalScrollbarSync() {
      this.internalScrollbarSyncEnabled = !this.internalScrollbarSyncEnabled;

      if (this.internalScrollbarSyncEnabled) {
        // 启用内部滚动条同步
        this.enableInternalScrollbarSync();
        this.$message.success('已启用内部滚动条同步 - 两个面板的滚动条将同步移动');
      } else {
        // 禁用内部滚动条同步，清除监听器
        this.clearInternalScrollbarListeners();

        // 禁用内部滚动条，使用CSS方法隐藏
        this.disableScrollbarTools();
        this.$message.info('已禁用内部滚动条同步 - 使用外部滚动条控制');
      }
    },
    editProperties() {
      this.showPropertiesDialog = true;

    },
    changeColor(val) {
      var colorMap = SeismicColors.getDefault().createNamedColorMap(val, 256)
      this.pipeline.setColorMap(colorMap);

      console.log(this.plots)
      if (this._seismicWidget) {
        this._seismicWidget.invalidate(); // 使组件重新渲染
        this._seismicWidget.fitToBounds(); // 调整视图以适应数据
      } else {
        console.error('Widget不可用，无法更新视图');
      }
      // 如果plots对象存在redraw方法，使用它来触发重绘
      if (this.plots && typeof this.plots.redraw === 'function') {
        this.plots.redraw();
      }
      //下方图

      this.pipelineBottom.setColorMap(colorMap);
      if (this._seismicWidgetBottom) {
        this._seismicWidgetBottom.invalidate(); // 使组件重新渲染
        this._seismicWidgetBottom.fitToBounds(); // 调整视图以适应数据
      } else {
        console.error('Widget不可用，无法更新视图');
      }
      // 如果plots对象存在redraw方法，使用它来触发重绘
      if (this.plotsBottom && typeof this.plotsBottom.redraw === 'function') {
        this.plotsBottom.redraw();
      }

    },
    //归一化
    changeNor(val) {
      if (this.NormalizationType == 7) {
        this.pipeline.setOptions({
          'normalization': {
            'type': this.NormalizationType,
            'scale': this.NormalizationBl
          }
        })
      } else {
        this.pipeline.setOptions({
          'normalization': {
            'type': this.NormalizationType,
            'scale': this.NormalizationBl
          }
        })
      }

      //下方图
      if (this.NormalizationType == 7) {
        this.pipelineBottom.setOptions({
          'normalization': {
            'type': this.NormalizationType,
            'scale': this.NormalizationBl
          }
        })
      } else {
        this.pipelineBottom.setOptions({
          'normalization': {
            'type': this.NormalizationType,
            'scale': this.NormalizationBl
          }
        })
      }
    },
    changeMycds() {

      this._seismicWidget.setScaleOptions({
        'tracescale': this.mycds,
        'samplescale': this.msycs,
        'deviceunit': 'in',
        'sampleunit': 's',
      });
    },
    changeInt() {
      console.log(this.pipeline.getOptions())
      this.pipeline.setOptions({
        'interpolation': {
          'samples': {
            "type": this.samplesType,//采样插值类型,
            "edge": this.samplesEdge,//采样插值边缘,
          },
          'traces': {
            "type": this.tracesType,//道插值类型
            "edge": this.tracesEdge,//道插值边缘
          },
        }
      })
      //下方图
      this.pipelineBottom.setOptions({
        'interpolation': {
          'samples': {
            "type": this.samplesType,//采样插值类型,
            "edge": this.samplesEdge,//采样插值边缘,
          },
          'traces': {
            "type": this.tracesType,//道插值类型
            "edge": this.tracesEdge,//道插值边缘
          },
        }
      })
    },
    changePlotType() {
      this.pipeline.setOptions({
        'plot': {
          'type': {
            "Wiggle": this.Wiggle,
            "Reversed": this.Reversed,
            "PositiveFill": this.PositiveFill,
            "NegativeFill": this.NegativeFill,
            "PositiveColorFill": this.PositiveColorFill,
            "NegativeColorFill": this.NegativeColorFill,
            "SimpleDensity": this.SimpleDensity,
            "InterpolatedDensity": this.InterpolatedDensity,
          },
          "clippingFactor": this.ClippingFactor,
          "decimationSpacing": this.DecimationSpacing,
          "densityDecimation": this.densityDecimation,
        },
        "clippingmode": this.ClippingMode,
        "dataProcessors": {
          "TaperFilter": {
            "apply": this.TaperFilterEnbled,
            "f1": Number(this.f1),
            "f2": Number(this.f2),
            "f3": Number(this.f3),
            "f4": Number(this.f4),
            "sampleRate": Number(this.sampleRate),
            "passFlag": this.passFlag,
          },
          "AGC": {
            "agcLength": this.AGCLength,
            "apply": this.AGCEnbled,
            "desiredAverage": this.DesiredAverage,
            "noiseReduction": this.NoiseReduction,
            "noiseReductionPercentage": this.NoiseReductionPercentage,
            "startSample": this.StartSample,
            "step": this.Step,
            "units": this.Units,
            "windowLength": this.WindowLength,
          },
          "Reverse": {
            "apply": this.ReverseEnbled,
            "inverted": this.inverted,
            "reversed": this.reversed,
          }
        }
      })
      console.log(this.pipeline.getOptions())
      //下方图
      this.pipelineBottom.setOptions({
        'plot': {
          'type': {
            "Wiggle": this.Wiggle,
            "Reversed": this.Reversed,
            "PositiveFill": this.PositiveFill,
            "NegativeFill": this.NegativeFill,
            "PositiveColorFill": this.PositiveColorFill,
            "NegativeColorFill": this.NegativeColorFill,
            "SimpleDensity": this.SimpleDensity,
            "InterpolatedDensity": this.InterpolatedDensity,
          },
          "clippingFactor": this.ClippingFactor,
          "decimationSpacing": this.DecimationSpacing,
          "densityDecimation": this.densityDecimation,
        },
        "clippingmode": this.ClippingMode,
        "dataProcessors": {
          "TaperFilter": {
            "apply": this.TaperFilterEnbled,
            "f1": Number(this.f1),
            "f2": Number(this.f2),
            "f3": Number(this.f3),
            "f4": Number(this.f4),
            "sampleRate": Number(this.sampleRate),
            "passFlag": this.passFlag,
          },
          "AGC": {
            "agcLength": this.AGCLength,
            "apply": this.AGCEnbled,
            "desiredAverage": this.DesiredAverage,
            "noiseReduction": this.NoiseReduction,
            "noiseReductionPercentage": this.NoiseReductionPercentage,
            "startSample": this.StartSample,
            "step": this.Step,
            "units": this.Units,
            "windowLength": this.WindowLength,
          },
          "Reverse": {
            "apply": this.ReverseEnbled,
            "inverted": this.inverted,
            "reversed": this.reversed,
          }
        }
      })
    },
  },

  beforeDestroy() {
    // 如果缩略图容器被移动到body，销毁前移回组件内，避免遗留
    try {
      if (this.$refs && this.$refs.thumbContainer && this.$refs.thumbContainer.parentNode === document.body) {
        const topActions = this.$el && this.$el.querySelector ? this.$el.querySelector('.top-actions') : null;
        if (topActions) {
          topActions.appendChild(this.$refs.thumbContainer);
        } else {
          document.body.removeChild(this.$refs.thumbContainer);
        }
      }
    } catch (e) { }
    // 清理滚动同步超时
    if (this._scrollSyncTimeout) {
      try { cancelAnimationFrame(this._scrollSyncTimeout); } catch (e) { }
      this._scrollSyncTimeout = null;
    }

    // 释放缩略图资源
    if (this.thumbResizeObserver) {
      try { this.thumbResizeObserver.disconnect(); } catch (e) { }
      this.thumbResizeObserver = null;
    }
    if (this.thumbChart) {
      try { this.thumbChart.dispose(); } catch (e) { }
      this.thumbChart = null;
    }
    // 清理内部滚动条监听器
    this.clearInternalScrollbarListeners();

    // 清理外层滚动条监听器（GeoToolkit 3.2.80兼容）
    this.clearOuterScrollbarListeners();

    // 清理DOM滚动条监听器
    this.clearDOMScrollbarListeners();

    // 停止滚动条同步监控
    this.stopScrollbarSyncMonitor();

    // 停止外层滚动条同步监控（GeoToolkit 3.2.80兼容）
    this.stopOuterScrollbarSyncMonitor();

    // 停止滚动条隐藏监控
    this.stopScrollbarHideMonitor();

    // 停止滚动条同步状态监控
    this.stopScrollbarSyncStatusMonitor();

    // 停止强力滚动条监控
    this.stopAggressiveScrollbarMonitor();

    // 清理独立容器
    const testContainer = document.getElementById('thumb-test-container');
    if (testContainer) {
      testContainer.remove();
    }
    const chartContainer = document.getElementById('thumb-chart-container');
    if (chartContainer) {
      chartContainer.remove();
    }

    // 清理资源
    if (this.plots) {
      this.plots.dispose();
    }
    if (this.annotationTool) {
      this.annotationTool.dispose();
    }
    if (this.pencilTool) {
      this.pencilTool.dispose();
    }

    // 移除右键菜单事件监听
    if (this.$refs.plot) {
      this.$refs.plot.removeEventListener('contextmenu', this.showContextMenu);
    }
    if (this.$refs.plot2) {
      this.$refs.plot2.removeEventListener('contextmenu', this.showContextMenu);
    }
    if (this._contextMenuClickBound) {
      document.removeEventListener('click', this.hideContextMenu);
      this._contextMenuClickBound = false;
    }
    // 移除键盘事件监听
    window.removeEventListener('keydown', this.handleKeyDown);

    // 移除鼠标悬停相关事件
    if (this.$refs.plot) {
      this.$refs.plot.removeEventListener('mouseenter', () => {
        this.isHovering = true;
      });
      this.$refs.plot.removeEventListener('mouseleave', () => {
        this.isHovering = false;
      });
      this.$refs.plot.removeEventListener('mousemove', this.handleMouseMove);
    }

    if (this.timerInterval) {
      clearTimeout(this.timerInterval);
    }

    // 停止滚动条监控
    this.stopScrollbarMonitor();
  }

}
</script>

<style scoped>
.app-containers {
  padding: 10px;
  height: 90vh !important;
}

/* 顶部操作与缩略图 */
.top-actions {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  /* 顶部操作与地震图拉开距离 */
  min-width: 100%;
  /* 确保有足够宽度 */
  overflow: visible;
  /* 允许内容溢出显示 */
  position: relative;
  z-index: 20;
  /* border: 1px solid blue; */
  /* 确保不被地震图覆盖 */
}

.left-actions .el-button+.el-button {
  margin-left: 8px;
}

.left-actions {
  padding-right: 280px;
}

.right-thumb {
  position: fixed;
  /* 固定在视口右上角 */
  top: 150px;
  right: 40px;
  width: 280px;
  background: #fff;
  border: 1px solid rgba(0, 0, 0, 0.15);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15), 0 2px 8px rgba(0, 0, 0, 0.1);
  z-index: 9999;
  /* 确保在画布之上 */
  border-radius: 4px;
  transition: box-shadow 0.3s ease;
}

.right-thumb:hover {
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2), 0 4px 12px rgba(0, 0, 0, 0.15);
}

.thumb-title {
  font-size: 12px;
  color: #666;
  padding: 6px 8px;
  border-bottom: 1px solid #eee;
}

.thumb-holder {
  flex: none;
  /* 改为固定尺寸，不使用flex: 1 */
  width: 260px;
  height: 160px;
  /* 固定高度，确保 ECharts 有可用高度 */
  background: #ffffff;
  /* 白色背景更明显 */
  /* border: 1px solid #409eff; */
  /* 与父容器一致的边框 */
  position: relative;
  min-width: 260px;
  min-height: 160px;
  max-width: 260px;
  max-height: 160px;
  overflow: hidden;
  /* 防止内容溢出 */
}

/* 固定定位的缩略图，确保始终可见 */
/* 移除模板内固定块样式（改为全局 body 容器） */

/* 可拖动的缩略图样式 */
.draggable-thumb {
  cursor: grab;
  user-select: none;
  transition: none;
  /* 拖动时禁用过渡动画 */
}

.draggable-thumb:active {
  cursor: grabbing;
}

.drag-handle {
  position: absolute;
  top: 5px;
  right: 5px;
  width: 20px;
  height: 20px;
  background: rgba(0, 0, 0, 0.6);
  color: white;
  border-radius: 3px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  cursor: grab;
  z-index: 10;
  opacity: 0.7;
  transition: opacity 0.2s;
}

.drag-handle:hover {
  opacity: 1;
  background: rgba(0, 0, 0, 0.8);
}

.drag-handle:active {
  cursor: grabbing;
}

/* 双画布容器与滚动/缩放 */
.split-container {
  display: flex;
  flex-direction: column;
  gap: 20px;
  /* 与顶部操作区留出更大空隙 */
}

.split-container.layout-vertical {
  flex-direction: column;
}

.split-container.layout-horizontal {
  flex-direction: row;
}

.split-container.layout-horizontal .sync-section {
  height: calc(84vh - 20px);
}

.sync-section {
  width: 100%;
  height: calc(42vh - 20px);
  overflow-x: auto;
  overflow-y: auto;
  border: 1px solid #eee;
  background: #fff;
}

/* 彻底隐藏 GeoToolkit-js 2.0 内部滚动条 */
.sync-section *[class*="scrollbar"],
.sync-section *[class*="Scrollbar"],
.sync-section *[class*="scroll"],
.sync-section *[class*="Scroll"],
.sync-section *[class*="geotoolkit.controls.tools.scroll"],
.sync-section .gt-scrollbar,
.sync-section .gt-scrollbar-horizontal,
.sync-section .gt-scrollbar-vertical {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  position: absolute !important;
  left: -9999px !important;
  top: -9999px !important;
  pointer-events: none !important;
}

/* 仅作用于本页面地震图区域，避免影响全局布局（如左侧菜单） */
.app-container .sync-section *[class*="scrollbar"],
.app-container .sync-section *[class*="Scrollbar"],
.app-container .sync-section *[class*="scroll"],
.app-container .sync-section *[class*="Scroll"],
.app-container .sync-section *[class*="geotoolkit.controls.tools.scroll"],
.app-container .sync-section .gt-scrollbar,
.app-container .sync-section .gt-scrollbar-horizontal,
.app-container .sync-section .gt-scrollbar-vertical {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  position: absolute !important;
  left: -9999px !important;
  top: -9999px !important;
  pointer-events: none !important;
}

.zoom-wrapper {
  width: 100%;
  display: inline-block;
  transform-origin: top left;
}

.plot-canvas {
  /* width: 100% !important; */
  height: calc(85vh - 100px) !important;
  /* margin-top: 20px; */
  transform-origin: top left;
}

.toolbar {
  padding: 10px;
  border-bottom: 1px solid #ddd;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: nowrap;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-grow: 1;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-left: auto;
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* 左侧操作按钮样式 - 现代渐变风格 */
.left-actions .el-button {
  height: 32px;
  padding: 0 14px;
  border-radius: 6px;
  border: none;
  font-size: 12px;
  font-weight: 500;
  color: #fff;
  background: linear-gradient(135deg, #409EFF 0%, #66b1ff 50%, #85c1ff 100%);
  box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
  letter-spacing: 0.3px;
}

.left-actions .el-button::before {
  content: '';
  position: absolute;
  top: 0;
  left: -100%;
  width: 100%;
  height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
  transition: left 0.5s ease;
}

.left-actions .el-button:hover {
  background: linear-gradient(135deg, #337ecc 0%, #5a9eff 50%, #73b5ff 100%);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.35);
  transform: translateY(-2px);
}

.left-actions .el-button:hover::before {
  left: 100%;
}

.left-actions .el-button:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
}

/* 右侧工具栏按钮样式 - 精致图标按钮 */
.toolbar-right .el-button {
  width: 40px;
  height: 40px;
  padding: 0;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 0;
  border: none;
  background: linear-gradient(145deg, #f8f9fa 0%, #e9ecef 100%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08),
  inset 0 1px 0 rgba(255, 255, 255, 0.8);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  overflow: hidden;
}

.toolbar-right .el-button [class^="el-icon-"] {
  font-size: 16px;
  margin: 0;
  color: #6c757d;
  transition: all 0.3s ease;
}

/* 绘制文本按钮 - 简化橙色系 */
.toolbar-right .el-button:has(.el-icon-edit-outline) [class^="el-icon-"] {
  color: #ff8c00;
}

.toolbar-right .el-button:has(.el-icon-edit-outline):hover {
  background: linear-gradient(145deg, #ff8c00 0%, #ffa500 100%);
  box-shadow: 0 4px 12px rgba(255, 140, 0, 0.25),
  0 2px 4px rgba(0, 0, 0, 0.1);
}

.toolbar-right .el-button:has(.el-icon-edit-outline):hover [class^="el-icon-"] {
  color: #fff;
}

.toolbar-right .el-button:has(.el-icon-edit-outline).active {
  background: linear-gradient(145deg, #ff8c00 0%, #ffa500 100%);
  box-shadow: 0 6px 16px rgba(255, 140, 0, 0.3),
  inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.toolbar-right .el-button:has(.el-icon-edit-outline).active [class^="el-icon-"] {
  color: #fff;
}

/* 绘制线条按钮 - 简化绿色系 */
.toolbar-right .el-button:has(.el-icon-edit) [class^="el-icon-"] {
  color: #28a745;
}

.toolbar-right .el-button:has(.el-icon-edit):hover {
  background: linear-gradient(145deg, #28a745 0%, #34ce57 100%);
  box-shadow: 0 4px 12px rgba(40, 167, 69, 0.25),
  0 2px 4px rgba(0, 0, 0, 0.1);
}

.toolbar-right .el-button:has(.el-icon-edit):hover [class^="el-icon-"] {
  color: #fff;
}

.toolbar-right .el-button:has(.el-icon-edit).active {
  background: linear-gradient(145deg, #28a745 0%, #34ce57 100%);
  box-shadow: 0 6px 16px rgba(40, 167, 69, 0.3),
  inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.toolbar-right .el-button:has(.el-icon-edit).active [class^="el-icon-"] {
  color: #fff;
}

/* 同步按钮 - 紫色系 */
.toolbar-right .el-button:has(.el-icon-s-operation) {
  background: linear-gradient(145deg, #f3e5f5 0%, #e1bee7 100%);
}

.toolbar-right .el-button:has(.el-icon-s-operation) [class^="el-icon-"] {
  color: #9c27b0;
}

.toolbar-right .el-button:has(.el-icon-s-operation):hover {
  background: linear-gradient(145deg, #9c27b0 0%, #ba68c8 100%);
  box-shadow: 0 4px 12px rgba(156, 39, 176, 0.25),
  0 2px 4px rgba(0, 0, 0, 0.1);
}

.toolbar-right .el-button:has(.el-icon-s-operation):hover [class^="el-icon-"] {
  color: #fff;
}

.toolbar-right .el-button:has(.el-icon-s-operation).active {
  background: linear-gradient(145deg, #9c27b0 0%, #ba68c8 100%);
  box-shadow: 0 6px 16px rgba(156, 39, 176, 0.3),
  inset 0 1px 0 rgba(255, 255, 255, 0.2);
}

.toolbar-right .el-button:has(.el-icon-s-operation).active [class^="el-icon-"] {
  color: #fff;
}

.toolbar-right .el-button::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
  opacity: 0;
  transition: opacity 0.3s ease;
  border-radius: 10px;
}

.toolbar-right .el-button:hover {
  background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
  box-shadow: 0 4px 12px rgba(64, 158, 255, 0.25),
  0 2px 4px rgba(0, 0, 0, 0.1);
  transform: translateY(-1px);
}

.toolbar-right .el-button:hover::before {
  opacity: 0;
}

.toolbar-right .el-button:hover [class^="el-icon-"] {
  color: #fff;
  transform: scale(1.1);
}

.toolbar-right .el-button.active {
  background: linear-gradient(145deg, #409EFF 0%, #66b1ff 100%);
  box-shadow: 0 6px 16px rgba(64, 158, 255, 0.3),
  inset 0 1px 0 rgba(255, 255, 255, 0.2);
  transform: translateY(-1px);
}

.toolbar-right .el-button.active [class^="el-icon-"] {
  color: #fff;
}

.toolbar-right .el-button:active {
  transform: translateY(0);
  box-shadow: 0 2px 6px rgba(64, 158, 255, 0.25);
}

/* 统一按钮样式 - 保持原有结构 */
.toolbar .el-button {
  width: 40px;
  height: 40px;
  padding: 10px;
  border-radius: 4px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 0;
}

.toolbar .el-button [class^="el-icon-"] {
  font-size: 16px;
  margin: 0;
}

.toolbar .el-button:not(.el-button--text) {
  border: 1px solid #ddd;
  background-color: #fff;
}

.toolbar .el-button-group .el-button {
  margin-right: -1px;
}

.toolbar .el-button-group .el-button:first-child {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

.toolbar .el-button-group .el-button:last-child {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
  margin-right: 0;
}

.toolbar .el-button-group .el-button:not(:first-child):not(:last-child) {
  border-radius: 0;
}

.toolbar .el-button:hover {
  background-color: #e6e6e6;
}

.toolbar .el-button.active {
  background-color: #e6e6e6;
  border-color: #adadad;
  color: #409eff;
}

/* 鼠标悬停信息面板样式 */
.cursor-info-panel {
  display: none;
}

.cs_status_bar {
  display: none;
}

.info-pill {
  display: none;
}

/* 样式面板相关样式 */
.style-panel {
  position: fixed;
  right: -300px;
  top: 0;
  width: 300px;
  height: 100vh;
  background-color: #fff;
  box-shadow: -2px 0 5px rgba(0, 0, 0, 0.1);
  transition: right 0.3s ease;
  z-index: 1000;
  overflow-y: auto;
}

.style-panel-visible {
  right: 0;
}

.style-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 15px;
  border-bottom: 1px solid #ddd;
}

.style-panel-header h3 {
  margin: 0;
  font-size: 16px;
}

.style-content {
  padding: 15px;
}

.style-section-title {
  font-weight: bold;
  margin: 10px 0;
  color: #333;
}

.style-item {
  margin-bottom: 15px;
}

.style-label {
  display: block;
  margin-bottom: 5px;
  color: #666;
}

.style-divider {
  height: 1px;
  background-color: #eee;
  margin: 15px 0;
}

.text-style-buttons {
  display: flex;
  gap: 5px;
}

.pattern-preview-fill {
  width: 100%;
  height: 24px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

/* 调整滑块和输入框的样式 */
.el-slider {
  margin-top: 8px;
}

.el-input-number {
  width: 100%;
}

.el-select {
  width: 100%;
}

.el-color-picker {
  width: 100%;
}

/* 添加错误和加载状态样式 */
.error-message {
  color: red;
  padding: 10px;
  margin: 10px;
  background-color: #fff3f3;
  border: 1px solid #ffa7a7;
  border-radius: 4px;
}

.loading-message {
  text-align: center;
  padding: 20px;
  color: #666;
}

.color-maps {
  margin-right: 10px;
}

.color-maps .el-select {
  width: 140px;
}

.color-maps-label {
  margin-right: 8px;
  font-size: 14px;
  color: #666;
}

.toolbar-controls {
  display: flex;
  align-items: center;
  gap: 10px;
}

.is-active {
  background-color: #e6e6e6;
  border-color: #adadad;
}

.context-menu {
  position: fixed;
  background-color: #fff;
  border: 1px solid #ddd;
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  z-index: 1001;
  padding: 5px 0;
}

.context-menu-separator {
  height: 1px;
  background-color: #eee;
  margin: 5px 0;
}

.context-menu-item {
  padding: 8px 16px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 14px;
  color: #333;
}

.context-menu-item:hover {
  background-color: #f5f5f5;
}

.context-menu-item.disabled {
  color: #999;
  cursor: not-allowed;
}

.context-menu-item.disabled:hover {
  background-color: transparent;
}

.shortcut {
  font-size: 12px;
  color: #999;
  margin-left: 16px;
}

.pattern-preview-line {
  width: 100%;
  height: 20px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

/* 响应式布局调整 */
@media (max-width: 768px) {
  .toolbar {
    flex-direction: column;
    align-items: flex-start;
  }

  .toolbar-left,
  .toolbar-right {
    width: 100%;
    margin: 5px 0;
  }

  .toolbar-right {
    margin-top: 10px;
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
  }

  .color-maps {
    margin-right: 0;
  }
}

.color-map-option {
  display: flex;
  align-items: center;
  gap: 8px;
}

.color-map-preview {
  width: 40px;
  height: 20px;
  border: 1px solid #ddd;
  border-radius: 2px;
}

.WhiteBlack {
  background: linear-gradient(to right, white, black);
}

.CustomGrayScale {
  background: linear-gradient(to right,
  rgb(255, 255, 255) 50%,
    /* -4000到181保持白色 */
  rgb(253, 253, 253) 55%,
    /* 181开始的颜色 */
  rgb(240, 240, 240) 65%,
    /* 到566的颜色 */
  rgb(180, 180, 180) 80%,
    /* 566后的过渡色 */
  rgb(6, 6, 6) 100%
    /* 最终颜色 */
  );
}

.CustomRedScale {
  background: linear-gradient(to right,
  #f62814,
  #dd8b66,
  #d7c692,
  #fbfaff,
  #6e6e8a,
  #323136);
}

.BlueWhiteRed {
  background: linear-gradient(to right, #0000ff, #ffffff, #ff0000);
}

.Rainbow {
  background: linear-gradient(to right,
  #ff0000,
  #ffff00,
  #00ff00,
  #00ffff,
  #0000ff,
  #ff00ff,
  #ff0000);
}

.Jet {
  background: linear-gradient(to right,
  #00008f,
  #0000ff,
  #00ffff,
  #00ff00,
  #ffff00,
  #ff7f00,
  #ff0000,
  #7f0000);
}

.Hot {
  background: linear-gradient(to right, #000000, #ff0000, #ffff00, #ffffff);
}

.Cool {
  background: linear-gradient(to right, #00ffff, #ff00ff);
}

/* 在style标签中添加 */
.cs_status_bar {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cs_status_bar section {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* 状态栏样式优化 */
.cs_status_bar {
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
  font-size: 12px !important;
  font-family: monospace !important;
}

.cs_status_bar section {
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
  padding: 0 5px !important;
  max-width: 120px !important;
}

.cs_status_bar section span {
  display: inline-block !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
  max-width: 100% !important;
}

/* 确保状态栏容器不会过度扩展 */
.gt-statusbar {
  max-width: 100% !important;
  overflow: hidden !important;
}

.gt-statusbar-section {
  max-width: 120px !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
}

/* 状态栏样式 */
.gt-statusbar {
  font-family: monospace !important;
  font-size: 12px !important;
  background-color: #f5f5f5 !important;
  border-top: 1px solid #ddd !important;
  height: 25px !important;
  line-height: 25px !important;
  padding: 0 10px !important;
}

.gt-statusbar-section {
  display: inline-block !important;
  margin-right: 15px !important;
  min-width: 80px !important;
  max-width: 80px !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
}

.gt-statusbar-section:last-child {
  margin-right: 0 !important;
}

/* 隐藏 GeoToolkit 内部滚动条，仅使用外层滚动 */
.gt-scrollbar,
.gt-scrollbar-horizontal,
.gt-scrollbar-vertical,
[class*="scrollbar"],
[class*="Scrollbar"],
.scrollbar,
.scrollbar-horizontal,
.scrollbar-vertical,
[class*="Scroll"],
[class*="scroll"] {
  display: none !important;
  visibility: hidden !important;
  pointer-events: none !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  overflow: hidden !important;
  position: absolute !important;
  left: -9999px !important;
  top: -9999px !important;
}

/* 隐藏滚动条滑块和轨道 */
.scrollbar-thumb,
.scrollbar-track,
.gt-scrollbar-thumb,
.gt-scrollbar-track,
  /* 仅在地震图可滚动区域内隐藏内部滚动条相关"thumb/track"，避免误伤缩略图 */
.sync-section [class*="thumb"]:not(.thumb-holder):not(.thumb-title):not(.right-thumb),
.sync-section [class*="track"] {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
}

/* 隐藏滚动条容器 */
[class*="scroll-container"],
[class*="ScrollContainer"],
.scroll-container {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
}

/* 隐藏所有可能的滚动条容器 */
.gt-widget [class*="scrollbar"],
.gt-plot [class*="scrollbar"],
.gt-seismic [class*="scrollbar"],
.gt-widget [class*="Scroll"],
.gt-plot [class*="Scroll"],
.gt-seismic [class*="Scroll"] {
  display: none !important;
  visibility: hidden !important;
  pointer-events: none !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
}

/* 针对GeoToolkit特定滚动条类名的强制隐藏 */
*[class="geotoolkit.controls.tools.scroll.HorizontalScroll"],
*[class="geotoolkit.controls.tools.scroll.VerticalScroll"] {
  display: none !important;
  visibility: hidden !important;
  opacity: 0 !important;
  width: 0 !important;
  height: 0 !important;
  pointer-events: none !important;
  position: absolute !important;
  left: -9999px !important;
  top: -9999px !important;
}

/* 外层滚动区域样式*/
.sync-section {
  pointer-events: auto !important;
}

.sync-section::-webkit-scrollbar {
  width: 4px;
  height: 4px;
}

.sync-section::-webkit-scrollbar-track {
  background: #f1f1f1;
}

.sync-section::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 3px;
}

.sync-section::-webkit-scrollbar-thumb:hover {
  background: #555;
}
</style>

<style>
.thumb-holder {
  flex: none;
  width: 260px;
  height: 160px;
  background: #ffffff;
  position: relative;
  min-width: 260px;
  min-height: 160px;
  max-width: 260px;
  max-height: 160px;
  overflow: hidden;
}

/* 缩略图弹窗样式 - 确保不被遮挡 */
.thumbnail-dialog {
  z-index: 9999999 !important;
}

.thumbnail-dialog .el-dialog {
  z-index: 9999999 !important;
}

.thumbnail-dialog .el-dialog__wrapper {
  z-index: 9999999 !important;
}

.thumbnail-dialog .el-overlay {
  z-index: 9999998 !important;
}

/* 确保弹窗内容完全可见 */
.thumbnail-dialog .el-dialog__body {
  overflow: visible !important;
  max-height: none !important;
}

/* 修复可能的容器遮挡问题 */
.app-containers {
  overflow: visible !important;
}

.containerBlock {
  overflow: visible !important;
}
</style>
