<template>
  <div ref="playgroundContainer" class="playground-container" :class="{ 'dark-theme': isDarkMode, 'fullscreen': isFullscreen, 'is-mobile': isMobile }">
    <!-- 加载动画 + 进度条 -->
    <div v-if="loading" class="playground-loading-overlay">
      <div class="playground-loading-card">
        <div class="loading-icon">
          <el-icon class="is-loading" :size="40"><Loading /></el-icon>
        </div>
        <div class="loading-text">正在加载编辑器和编译器...</div>
        <div class="loading-bar">
          <div class="loading-bar-inner" :style="{ width: loadProgress + '%' }"></div>
        </div>
        <div class="loading-percent">{{ loadProgress }}%</div>
        <div class="loading-details">{{ loadingMessage }}</div>
      </div>
    </div>

    <!-- 密码验证界面 -->
    <div v-if="!loading && authChecking" class="playground-auth-loading">
      <el-icon class="is-loading" :size="30"><Loading /></el-icon>
      <span style="margin-left: 10px;">正在检查访问权限...</span>
    </div>

    <!-- 演练场禁用提示 -->
    <div v-if="!loading && !authChecking && !playgroundEnabled" class="playground-auth-overlay">
      <div class="playground-auth-card">
        <div class="auth-icon" style="color: #f56c6c;">
          <el-icon :size="50"><WarningFilled /></el-icon>
        </div>
        <div class="auth-title">演练场功能已禁用</div>
        <div class="auth-subtitle">请联系管理员启用演练场功能</div>
        <el-button type="primary" size="large" @click="goHome" class="auth-button">
          <span>返回首页</span>
        </el-button>
      </div>
    </div>

    <div v-if="shouldShowAuthUI" class="playground-auth-overlay">
      <div class="playground-auth-card">
        <div class="auth-icon">
          <el-icon :size="50"><Lock /></el-icon>
        </div>
        <div class="auth-title">脚本解析器演练场</div>
        <div class="auth-subtitle">请输入访问密码</div>
        <el-input
          v-model="inputPassword"
          type="password"
          placeholder="请输入访问密码"
          size="large"
          @keyup.enter="submitPassword"
          class="auth-input"
        >
          <template #prefix>
            <el-icon><Lock /></el-icon>
          </template>
        </el-input>
        <div v-if="authError" class="auth-error">
          <el-icon><WarningFilled /></el-icon>
          <span>{{ authError }}</span>
        </div>
        <el-button type="primary" size="large" @click="submitPassword" :loading="authLoading" class="auth-button">
          <el-icon v-if="!authLoading"><Unlock /></el-icon>
          <span>确认登录</span>
        </el-button>
      </div>
    </div>

    <div class="header-left">
            <div class="header-left-top">
              <!-- 面包屑导航 -->
              <el-breadcrumb separator="/" class="breadcrumb-nav">
                <el-breadcrumb-item>
                  <el-link :underline="false" @click="goHomeInNewWindow" class="breadcrumb-link">
                    <el-icon><HomeFilled /></el-icon>
                    <span style="margin-left: 4px;">首页</span>
                  </el-link>
                </el-breadcrumb-item>
                <el-breadcrumb-item>脚本解析器演练场 <span style="color: var(--el-text-color-secondary); font-size: 12px;">
                JavaScript (ES5)
              </span></el-breadcrumb-item>
              </el-breadcrumb>
            </div>
          </div>
          
    <!-- 原有内容 - 只在已认证时显示 -->
    <el-card v-if="authed && !loading" class="playground-card">
      <template #header>
        <div class="card-header">
          <div class="header-actions">
            <!-- 主要操作 -->
            <el-button-group size="small" style="margin-left: 10px;">
              <el-tooltip content="运行测试 (Ctrl+Enter)" placement="bottom">
                <el-button :icon="testing ? 'Loading' : 'CaretRight'" @click="executeTest" :loading="testing">
                  运行
                </el-button>
              </el-tooltip>
              <el-tooltip content="保存代码 (Ctrl+S)" placement="bottom">
                <el-button icon="Document" @click="saveCode">保存</el-button>
              </el-tooltip>
              <el-tooltip content="格式化代码 (Shift+Alt+F)" placement="bottom">
                <el-button icon="MagicStick" @click="formatCode">格式化</el-button>
              </el-tooltip>
            </el-button-group>
            
            <!-- IDE功能按钮 -->
            <el-button-group size="small" style="margin-left: 10px;">
              <el-tooltip content="新建文件 (Ctrl+N)" placement="bottom">
                <el-button icon="DocumentAdd" @click="showNewFileDialog">新建</el-button>
              </el-tooltip>
              <el-tooltip content="复制全部 (Ctrl+A, Ctrl+C)" placement="bottom">
                <el-button icon="CopyDocument" @click="copyAll">复制全部</el-button>
              </el-tooltip>
              <el-tooltip content="全选 (Ctrl+A)" placement="bottom">
                <el-button icon="Select" @click="selectAll">全选</el-button>
              </el-tooltip>
              <el-tooltip :content="editorOptions.wordWrap === 'on' ? '关闭自动换行' : '开启自动换行'" placement="bottom">
                <el-button :icon="editorOptions.wordWrap === 'on' ? 'Operation' : 'Sort'" @click="toggleWordWrap">
                  {{ editorOptions.wordWrap === 'on' ? '换行' : '不换行' }}
                </el-button>
              </el-tooltip>
            </el-button-group>
            
            <!-- 主题切换 -->
            <el-dropdown size="small" @command="changeTheme" style="margin-left: 10px;">
              <el-button size="small">
                <el-icon><component :is="themes.find(t => t.name === currentTheme)?.icon || 'Sunny'" /></el-icon>
                <span style="margin-left: 5px;">{{ currentTheme }}</span>
              </el-button>
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item v-for="theme in themes" :key="theme.name" :command="theme.name">
                    <el-icon><component :is="theme.icon" /></el-icon>
                    <span style="margin-left: 5px;">{{ theme.name }}</span>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
            
            <!-- 全屏 -->
            <el-tooltip content="全屏模式 (F11)" placement="bottom">
              <el-button size="small" :icon="isFullscreen ? 'FullScreen' : 'FullScreen'" @click="toggleFullscreen" />
            </el-tooltip>
            
            <!-- 更多操作 -->
            <el-dropdown size="small" style="margin-left: 5px;">
              <el-button size="small" icon="More" />
              <template #dropdown>
                <el-dropdown-menu>
                  <el-dropdown-item icon="DocumentAdd" @click="loadTemplate">加载示例 (Ctrl+R)</el-dropdown-item>
                  <el-dropdown-item icon="Delete" @click="clearCode">清空代码</el-dropdown-item>
                  <el-dropdown-item icon="Download" @click="exportCurrentFile">导出当前JS</el-dropdown-item>
                  <el-dropdown-item icon="Promotion" @click="publishParser">发布脚本</el-dropdown-item>
                  <el-dropdown-item icon="QuestionFilled" @click="showShortcutsHelp">快捷键 (Ctrl+/)</el-dropdown-item>
                </el-dropdown-menu>
              </template>
            </el-dropdown>
          </div>
        </div>
      </template>

      <el-tabs v-model="activeTab" @tab-change="handleTabChange">
        <!-- 代码编辑标签页 -->
        <el-tab-pane label="代码编辑" name="editor">
          <!-- 文件标签页 -->
          <div class="file-tabs-container">
            <div class="file-tabs-wrapper">
              <el-tabs 
                v-model="activeFileId" 
                type="card" 
                closable 
                @tab-remove="removeFile"
                @tab-change="handleFileChange"
                class="file-tabs"
              >
                <el-tab-pane
                  v-for="file in files"
                  :key="file.id"
                  :label="file.name + (file.modified ? ' *' : '')"
                  :name="file.id"
                >
                </el-tab-pane>
              </el-tabs>
              <el-tooltip content="新建文件" placement="bottom">
                <el-button 
                  icon="Plus" 
                  size="small" 
                  circle
                  @click="showNewFileDialog"
                  class="new-file-tab-btn"
                />
              </el-tooltip>
            </div>
          </div>
          
          <!-- 移动端：不使用 splitpanes，内容自然向下流动 -->
          <div v-if="isMobile" class="mobile-layout">
            <!-- 编辑器区域 -->
            <div class="editor-section">
              <MonacoEditor
                ref="editorRef"
                v-model="currentCode"
                :theme="editorTheme"
                :height="'400px'"
                :options="editorOptions"
                @change="onCodeChange"
              />
              
              <!-- 移动端悬浮操作按钮 -->
              <div class="mobile-editor-actions">
                <el-button-group>
                  <el-tooltip content="撤销 (Ctrl+Z)" placement="top">
                    <el-button 
                      size="small" 
                      icon="RefreshLeft" 
                      circle
                      @click="undo"
                      class="editor-action-btn"
                    />
                  </el-tooltip>
                  <el-tooltip content="重做 (Ctrl+Y)" placement="top">
                    <el-button 
                      size="small" 
                      icon="RefreshRight" 
                      circle
                      @click="redo"
                      class="editor-action-btn"
                    />
                  </el-tooltip>
                  <el-tooltip content="格式化 (Shift+Alt+F)" placement="top">
                    <el-button 
                      size="small" 
                      icon="MagicStick" 
                      circle
                      @click="formatCode"
                      class="editor-action-btn"
                    />
                  </el-tooltip>
                  <el-tooltip content="全选 (Ctrl+A)" placement="top">
                    <el-button 
                      size="small" 
                      icon="Select" 
                      circle
                      @click="selectAll"
                      class="editor-action-btn"
                    />
                  </el-tooltip>
                </el-button-group>
              </div>
            </div>
            
            <!-- 测试参数和结果区域 -->
            <div v-if="!collapsedPanels.rightPanel" class="test-section mobile-test-section">
              <!-- 测试参数 -->
              <el-card class="test-params-card collapsible-card" shadow="never" style="margin-top: 12px">
                <template #header>
                  <div class="card-header-with-collapse">
                    <span>测试参数</span>
                    <el-button 
                      text 
                      size="small" 
                      :icon="collapsedPanels.testParams ? 'ArrowDown' : 'ArrowUp'"
                      @click="togglePanel('testParams')"
                    />
                  </div>
                </template>
                <transition name="collapse">
                  <div v-show="!collapsedPanels.testParams">
                    <el-form :model="testParams" label-width="0px" size="small" class="test-params-form">
                      <el-form-item label="" class="share-url-item">
                        <el-input
                          v-model="testParams.shareUrl"
                          placeholder="请输入分享链接"
                          clearable
                        />
                      </el-form-item>
                      <el-form-item label="" class="password-item">
                        <el-input
                          v-model="testParams.pwd"
                          placeholder="密码（可选）"
                          clearable
                        />
                      </el-form-item>
                      <el-form-item label="" class="method-item-horizontal">
                        <el-radio-group v-model="testParams.method" size="small">
                          <el-radio label="parse">parse</el-radio>
                          <el-radio label="parseFileList">parseFileList</el-radio>
                        </el-radio-group>
                      </el-form-item>
                      <el-form-item class="button-item">
                        <el-button
                          type="primary"
                          :loading="testing"
                          @click="executeTest"
                          style="width: 100%"
                        >
                          执行测试
                        </el-button>
                      </el-form-item>
                    </el-form>
                  </div>
                </transition>
              </el-card>

              <!-- 执行结果 -->
              <el-card class="result-card collapsible-card" shadow="never" style="margin-top: 10px">
                <template #header>
                  <div class="card-header-with-collapse">
                    <span>执行结果</span>
                    <el-button 
                      text 
                      size="small" 
                      :icon="collapsedPanels.testResult ? 'ArrowDown' : 'ArrowUp'"
                      @click="togglePanel('testResult')"
                    />
                  </div>
                </template>
                <transition name="collapse">
                  <div v-show="!collapsedPanels.testResult">
                    <div v-if="testResult" class="result-content">
                      <el-alert
                        :type="testResult.success ? 'success' : 'error'"
                        :title="testResult.success ? '执行成功' : '执行失败'"
                        :closable="false"
                        style="margin-bottom: 10px"
                      />
                      
                      <div v-if="testResult.success" class="result-section">
                        <div class="section-title">结果数据：</div>
                        <div v-if="testResult.result" class="result-debug-box">
                          <strong>结果内容：</strong>{{ testResult.result }}
                        </div>
                        <JsonViewer :value="testResult.result" :expand-depth="3" />
                      </div>

                      <div v-if="testResult.error" class="result-section">
                        <div class="section-title">错误信息：</div>
                        <el-alert type="error" :title="testResult.error" :closable="false" />
                        <div v-if="testResult.stackTrace" class="stack-trace">
                          <el-collapse>
                            <el-collapse-item title="查看堆栈信息" name="stack">
                              <pre>{{ testResult.stackTrace }}</pre>
                            </el-collapse-item>
                          </el-collapse>
                        </div>
                      </div>

                      <div v-if="testResult.executionTime" class="result-section">
                        <div class="section-title">执行时间：</div>
                        <div>{{ testResult.executionTime }}ms</div>
                      </div>
                    </div>
                    <div v-else class="empty-result">
                      <el-empty description="暂无执行结果" :image-size="80" />
                    </div>
                  </div>
                </transition>
              </el-card>
            </div>
          </div>

          <!-- 桌面端：使用 splitpanes -->
          <Splitpanes v-else class="default-theme" @resized="handleResize">
            <!-- 编辑器区域 (左侧) -->
            <Pane :size="collapsedPanels.rightPanel ? 100 : splitSizes[0]" min-size="30" class="editor-pane">
              <div class="editor-section">
                <MonacoEditor
                  ref="editorRef"
                  v-model="currentCode"
                  :theme="editorTheme"
                  :height="'100%'"
                  :options="editorOptions"
                  @change="onCodeChange"
                />
              </div>
            </Pane>

            <!-- 测试参数和结果区域 (右侧) -->
            <Pane v-if="!collapsedPanels.rightPanel" 
              :size="splitSizes[1]" min-size="20" class="test-pane" style="margin-left: 10px;">
              <div class="test-section">
                <!-- 优化的折叠按钮 -->
                <el-tooltip content="折叠测试面板" placement="left">
                  <div class="panel-collapse-btn" @click="toggleRightPanel">
                    <el-icon><CaretRight /></el-icon>
                  </div>
                </el-tooltip>
                <!-- 测试参数 -->
                <el-card class="test-params-card collapsible-card" shadow="never">
                  <template #header>
                    <div class="card-header-with-collapse">
                      <span>测试参数</span>
                      <el-button 
                        text 
                        size="small" 
                        :icon="collapsedPanels.testParams ? 'ArrowDown' : 'ArrowUp'"
                        @click="togglePanel('testParams')"
                      />
                    </div>
                  </template>
                  <transition name="collapse">
                    <div v-show="!collapsedPanels.testParams">
              <el-form :model="testParams" label-width="0px" size="small" class="test-params-form">
                <el-form-item label="" class="share-url-item">
                  <el-input
                    v-model="testParams.shareUrl"
                    placeholder="请输入分享链接"
                    clearable
                  />
                </el-form-item>
                <el-form-item label="" class="password-item">
                  <el-input
                    v-model="testParams.pwd"
                    placeholder="密码（可选）"
                    clearable
                  />
                </el-form-item>
                <el-form-item label="" class="method-item-horizontal">
                  <el-radio-group v-model="testParams.method" size="small">
                    <el-radio label="parse">parse</el-radio>
                    <el-radio label="parseFileList">parseFileList</el-radio>
                    <!-- <el-radio label="parseById">parseById</el-radio> -->
                  </el-radio-group>
                </el-form-item>
                <el-form-item class="button-item">
                  <el-button
                    type="primary"
                    :loading="testing"
                    @click="executeTest"
                    style="width: 100%"
                  >
                    执行测试
                  </el-button>
                </el-form-item>
              </el-form>
                    </div>
                  </transition>
                </el-card>

            <!-- 执行结果 -->
            <el-card class="result-card collapsible-card" shadow="never" style="margin-top: 10px">
              <template #header>
                <div class="card-header-with-collapse">
                  <span>执行结果</span>
                  <el-button 
                    text 
                    size="small" 
                    :icon="collapsedPanels.testResult ? 'ArrowDown' : 'ArrowUp'"
                    @click="togglePanel('testResult')"
                  />
                </div>
              </template>
              <transition name="collapse">
                <div v-show="!collapsedPanels.testResult">
              <div v-if="testResult" class="result-content">
                <el-alert
                  :type="testResult.success ? 'success' : 'error'"
                  :title="testResult.success ? '执行成功' : '执行失败'"
                  :closable="false"
                  style="margin-bottom: 10px"
                />
                
                <div v-if="testResult.success" class="result-section">
                  <div class="section-title">结果数据：</div>
                  <!-- 调试：直接显示 result -->
                  <div v-if="testResult.result" class="result-debug-box">
                    <strong>结果内容：</strong>{{ testResult.result }}
                  </div>
                  <JsonViewer :value="testResult.result" :expand-depth="3" />
                </div>

                <div v-if="testResult.error" class="result-section">
                  <div class="section-title">错误信息：</div>
                  <el-alert type="error" :title="testResult.error" :closable="false" />
                  <div v-if="testResult.stackTrace" class="stack-trace">
                    <el-collapse>
                      <el-collapse-item title="查看堆栈信息" name="stack">
                        <pre>{{ testResult.stackTrace }}</pre>
                      </el-collapse-item>
                    </el-collapse>
                  </div>
                </div>

                <div v-if="testResult.executionTime" class="result-section">
                  <div class="section-title">执行时间：</div>
                  <div>{{ testResult.executionTime }}ms</div>
                </div>
              </div>
              <div v-else class="empty-result">
                <el-empty description="暂无执行结果" :image-size="80" />
              </div>
                </div>
              </transition>
            </el-card>
              </div>
            </Pane>
          </Splitpanes>
          
          <!-- 优化的右侧面板展开按钮（当折叠时显示） -->
          <el-tooltip v-if="collapsedPanels.rightPanel" content="展开测试面板" placement="left">
            <div class="panel-expand-btn" @click="toggleRightPanel">
              <el-icon size="20"><CaretLeft /></el-icon>
            </div>
          </el-tooltip>

      <!-- 日志控制台（可折叠） -->
      <transition name="slide-up">
        <el-card v-show="!collapsedPanels.console" class="console-card collapsible-card" shadow="never" style="margin-top: 12px">
          <template #header>
            <div class="card-header-with-collapse">
              <div style="display: flex; align-items: center; gap: 10px;">
                <span>控制台日志</span>
                <el-tag size="small" type="info">{{ consoleLogs.length }}</el-tag>
              </div>
              <div style="display: flex; align-items: center; gap: 5px;">
                <el-tooltip content="清空控制台 (Ctrl+L)" placement="top">
                  <el-button size="small" text icon="Delete" @click="clearConsoleLogs">清空</el-button>
                </el-tooltip>
                <el-tooltip content="折叠控制台" placement="top">
                  <el-button 
                    text 
                    size="small" 
                    icon="ArrowDown"
                    @click="togglePanel('console')"
                  />
                </el-tooltip>
              </div>
            </div>
          </template>
          <div class="console-container">
            <div
              v-for="(log, index) in consoleLogs"
              :key="index"
              :class="[
                'console-entry', 
                'console-' + log.level.toLowerCase(),
                log.source === 'JS' ? 'console-js-source' : 'console-java-source'
              ]"
            >
              <span class="console-time">{{ formatTime(log.timestamp) }}</span>
              <span class="console-level">{{ log.level }}</span>
              <span v-if="log.source === 'JS'" class="console-source-tag">[JS]</span>
              <span class="console-message">{{ log.message }}</span>
            </div>
            <div v-if="consoleLogs.length === 0" class="empty-console">
              <span>暂无日志</span>
            </div>
          </div>
        </el-card>
      </transition>
      
      <!-- 控制台展开按钮（当折叠时显示） -->
      <transition name="fade">
        <div v-if="collapsedPanels.console" class="console-expand-btn" @click="togglePanel('console')">
          <el-icon size="16"><Top /></el-icon>
          <span style="margin-left: 5px;">控制台 ({{ consoleLogs.length }})</span>
        </div>
      </transition>

          <!-- 使用说明（可折叠） -->
          <el-card class="help-card collapsible-card" shadow="never" style="margin-top: 12px">
            <template #header>
              <div class="card-header-with-collapse">
                <span>📖 使用说明</span>
                <el-button 
                  text 
                  size="small" 
                  :icon="collapsedPanels.help ? 'ArrowDown' : 'ArrowUp'"
                  @click="togglePanel('help')"
                />
              </div>
            </template>
            <transition name="collapse">
              <div v-show="!collapsedPanels.help">
              <div class="help-content">
                <h3>什么是脚本解析器演练场？</h3>
                <p>演练场允许您快速编写、测试和发布JavaScript解析脚本，无需重启服务器即可调试和验证解析逻辑。</p>
                
                <h3>快速开始</h3>
                <ol>
                  <li>点击"加载示例"查看示例代码模板</li>
                  <li>修改代码中的解析逻辑</li>
                  <li>输入测试URL和密码，点击"执行测试"验证代码</li>
                  <li>测试通过后，点击"发布脚本"保存到数据库</li>
                </ol>

                <h3>脚本格式要求</h3>
                <ul>
                  <li>必须包含元数据注释块（<code>// ==UserScript== ... // ==/UserScript==</code>）</li>
                  <li>必填元数据：<code>@name</code>、<code>@type</code>、<code>@displayName</code>、<code>@match</code></li>
                  <li><code>@type</code> 必须唯一，不能与现有解析器冲突</li>
                  <li><code>@match</code> 必须包含命名捕获组 <code>(?&lt;KEY&gt;...)</code></li>
                  <li>必须实现 <code>parse</code> 函数（必填）</li>
                  <li>可选实现 <code>parseFileList</code> 和 <code>parseById</code> 函数</li>
                </ul>

                <h3>API参考</h3>
                <ul>
                  <li><code>shareLinkInfo</code> - 分享链接信息对象，提供 <code>getShareUrl()</code>、<code>getShareKey()</code> 等方法</li>
                  <li><code>http</code> - HTTP客户端，提供 <code>get()</code>、<code>post()</code>、<code>sendJson()</code> 等方法</li>
                  <li><code>logger</code> - 日志对象，提供 <code>info()</code>、<code>debug()</code>、<code>error()</code> 等方法</li>
                </ul>

                <h3>发布脚本</h3>
                <ul>
                  <li>脚本会保存到数据库，最多可创建100个解析器</li>
                  <li>发布的解析器可以在"解析器列表"标签页中查看和管理</li>
                  <li>可以编辑、删除已发布的解析器</li>
                  <li>发布成功后会显示API调用示例，包含302重定向和JSON响应两种方式</li>
                </ul>

                <h3>📡 API调用方式</h3>
                <p>发布解析器后，可以通过以下API端点调用：</p>
                
                <h4>1. 302重定向（直接下载）</h4>
                <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">GET /parser?url=分享链接&pwd=密码</pre>
                <p style="color: #666; font-size: 13px;">返回302重定向到下载地址，浏览器会自动跳转下载</p>
                
                <h4>2. JSON响应（获取解析结果）</h4>
                <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">GET /json/parser?url=分享链接&pwd=密码</pre>
                <p style="color: #666; font-size: 13px;">返回JSON格式的解析结果，包含下载链接等详细信息</p>
                
                <h4>使用示例</h4>
                <div style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 10px 0;">
                  <p><strong>浏览器访问：</strong></p>
                  <code>http://localhost:6400/parser?url=https://lanzoui.com/i7Aq12ab3cd</code>
                </div>
                
                <div style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 10px 0;">
                  <p><strong>curl命令：</strong></p>
                  <code>curl "http://localhost:6400/json/parser?url=https://lanzoui.com/i7Aq12ab3cd"</code>
                </div>
                
                <div style="background: #f5f5f5; padding: 10px; border-radius: 4px; margin: 10px 0;">
                  <p><strong>JavaScript调用：</strong></p>
                  <code>fetch('/json/parser?url=' + encodeURIComponent(shareUrl))<br>
                  &nbsp;&nbsp;.then(res => res.json())<br>
                  &nbsp;&nbsp;.then(data => console.log(data.data.url))</code>
                </div>
                
                <p style="color: #e6a23c; margin-top: 10px;">
                  💡 <strong>提示：</strong>发布成功后会自动显示完整的API调用示例
                </p>

                <h3>注意事项</h3>
                <ul>
                  <li>演练场脚本与正式解析器隔离，不会影响现有解析器规则</li>
                  <li>所有HTTP请求都是同步的，不支持异步操作</li>
                  <li>仅支持ES5.1语法（Nashorn引擎限制）</li>
                  <li>建议在发布前充分测试脚本的正确性</li>
                </ul>

                <h3>📖 参考文档</h3>
                <p>更多详细信息，请参考 GitHub 仓库文档：</p>
                <ul>
                  <li>
                    <a href="https://github.com/qaiu/netdisk-fast-download/blob/main/parser/doc/JAVASCRIPT_PARSER_GUIDE.md" target="_blank" rel="noopener noreferrer">
                      JavaScript 解析器开发指南
                    </a>
                  </li>
                  <li>
                    <a href="https://github.com/qaiu/netdisk-fast-download/blob/main/parser/doc/CUSTOM_PARSER_GUIDE.md" target="_blank" rel="noopener noreferrer">
                      自定义解析器扩展指南
                    </a>
                  </li>
                  <li>
                    <a href="https://github.com/qaiu/netdisk-fast-download/blob/main/parser/doc/CUSTOM_PARSER_QUICKSTART.md" target="_blank" rel="noopener noreferrer">
                      快速开始教程
                    </a>
                  </li>
                  <li>
                    <a href="https://github.com/qaiu/netdisk-fast-download/blob/main/parser/README.md" target="_blank" rel="noopener noreferrer">
                      解析器模块文档
                    </a>
                  </li>
                </ul>
              </div>
              </div>
            </transition>
          </el-card>
        </el-tab-pane>

        <!-- 解析器列表标签页 -->
        <el-tab-pane label="解析器列表" name="list">
          <div class="parser-list-section">
            <el-table :data="parserList" v-loading="loadingList" style="width: 100%">
              <el-table-column prop="name" label="名称" width="150" />
              <el-table-column prop="type" label="类型标识" width="120" />
              <el-table-column prop="displayName" label="显示名称" width="150" />
              <el-table-column prop="author" label="作者" width="100" />
              <el-table-column prop="version" label="版本" width="80" />
              <el-table-column prop="createTime" label="创建时间" width="180">
                <template #default="scope">
                  {{ formatDateTime(scope.row.createTime) }}
                </template>
              </el-table-column>
              <el-table-column prop="enabled" label="状态" width="80">
                <template #default="scope">
                  <el-tag :type="scope.row.enabled ? 'success' : 'info'">
                    {{ scope.row.enabled ? '启用' : '禁用' }}
                  </el-tag>
                </template>
              </el-table-column>
              <el-table-column label="操作" width="120" fixed="right">
                <template #default="scope">
                  <el-button size="small" @click="loadParserToEditor(scope.row)">编辑</el-button>
                  <el-button size="small" type="danger" @click="deleteParser(scope.row.id)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
          </div>
        </el-tab-pane>
      </el-tabs>
    </el-card>

    <!-- 发布对话框 -->
    <el-dialog 
      v-model="publishDialogVisible" 
      title="发布解析器" 
      :width="isMobile ? '90%' : '600px'"
      :close-on-click-modal="false"
      class="publish-dialog"
    >
      <el-form :model="publishForm" :label-width="isMobile ? '80px' : '100px'">
        <el-form-item label="脚本代码">
          <el-input
            v-model="publishForm.jsCode"
            type="textarea"
            :rows="isMobile ? 8 : 10"
            readonly
            class="publish-code-textarea"
          />
        </el-form-item>
        <el-alert
          type="warning"
          :closable="false"
          style="margin-bottom: 20px"
          class="publish-alert"
        >
          <template #title>
            <div class="publish-checklist">
              <p style="margin-bottom: 8px; font-weight: 500;">发布前请确保：</p>
              <ul style="margin: 0; padding-left: 20px;">
                <li>脚本已通过测试</li>
                <li>元数据信息完整（@name, @type, @displayName, @match）</li>
                <li>类型标识（@type）唯一，不与现有解析器冲突</li>
                <li>当前解析器数量未超过100个</li>
              </ul>
            </div>
          </template>
        </el-alert>
      </el-form>
      <template #footer>
        <div class="dialog-footer-mobile">
          <el-button @click="publishDialogVisible = false" :size="isMobile ? 'default' : 'default'">取消</el-button>
          <el-button type="primary" :loading="publishing" @click="confirmPublish" :size="isMobile ? 'default' : 'default'">确认发布</el-button>
        </div>
      </template>
    </el-dialog>
    
    <!-- 新建文件对话框 -->
    <el-dialog 
      v-model="newFileDialogVisible" 
      title="新建解析器文件" 
      :width="isMobile ? '90%' : '600px'"
      :close-on-click-modal="false"
      class="new-file-dialog"
    >
      <el-form 
        ref="newFileFormRef"
        :model="newFileForm" 
        :rules="newFileFormRules"
        :label-width="isMobile ? '80px' : '100px'"
      >
        <el-form-item label="解析器名" prop="name">
          <el-input
            v-model="newFileForm.name"
            placeholder="例如: 示例解析器"
            clearable
          />
          <div class="form-tip">必填, 将作为文件名和@name</div>
        </el-form-item>
        <el-form-item label="标识" prop="identifier">
          <el-input
            v-model="newFileForm.identifier"
            placeholder="例如: example_parser"
            clearable
          />
          <div class="form-tip">必填, 将作为@type类型标识</div>
        </el-form-item>
        <el-form-item label="作者">
          <el-input
            v-model="newFileForm.author"
            placeholder="例如: yourname"
            clearable
          />
          <div class="form-tip">可选, 默认为 yourname</div>
        </el-form-item>
        <el-form-item label="域名匹配">
          <el-input
            v-model="newFileForm.match"
            placeholder="例如: https?://example.com/s/(?&lt;KEY&gt;\w+)"
            clearable
          />
          <div class="form-tip">可选, 正则表达式, 用于匹配分享链接URL</div>
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer-mobile">
          <el-button @click="newFileDialogVisible = false" :size="isMobile ? 'default' : 'default'">取消</el-button>
          <el-button type="primary" @click="createNewFile" :size="isMobile ? 'default' : 'default'">创建</el-button>
        </div>
      </template>
    </el-dialog>
    
    <!-- 快捷键帮助对话框 -->
    <el-dialog 
      v-model="shortcutsDialogVisible" 
      title="⌨️ 快捷键" 
      :width="isMobile ? '90%' : '500px'"
      class="shortcuts-dialog"
    >
      <el-table :data="shortcutsData" style="width: 100%" :show-header="false" class="shortcuts-table">
        <el-table-column prop="name" label="功能" :width="isMobile ? 120 : 200" />
        <el-table-column prop="keys" label="快捷键">
          <template #default="{ row }">
            <el-tag v-for="key in row.keys" :key="key" size="small" style="margin-right: 5px; margin-bottom: 4px;">
              {{ key }}
            </el-tag>
          </template>
        </el-table-column>
      </el-table>
      <template #footer>
        <el-button type="primary" @click="shortcutsDialogVisible = false" :size="isMobile ? 'default' : 'default'">知道了</el-button>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue';
import { ElMessage, ElMessageBox } from 'element-plus';
import { useMagicKeys, useFullscreen, useEventListener } from '@vueuse/core';
import { useRouter } from 'vue-router';
import { Splitpanes, Pane } from 'splitpanes';
import 'splitpanes/dist/splitpanes.css';
import MonacoEditor from '@/components/MonacoEditor.vue';
import { playgroundApi } from '@/utils/playgroundApi';
import { configureMonacoTypes, loadTypesFromApi } from '@/utils/monacoTypes';
import JsonViewer from 'vue3-json-viewer';

export default {
  name: 'Playground',
  components: {
    MonacoEditor,
    JsonViewer,
    Splitpanes,
    Pane
  },
  setup() {
    const router = useRouter();
    
    // 语言常量
    const LANGUAGE = {
      JAVASCRIPT: 'JavaScript'
    };

    const editorRef = ref(null);
    const jsCode = ref('');
    
    // ===== 多文件管理 =====
    const files = ref([
      { id: 'file1', name: '文件1.js', content: '', modified: false }
    ]);
    const activeFileId = ref('file1');
    const fileIdCounter = ref(1);
    
    // 获取当前活动文件
    const activeFile = computed(() => {
      return files.value.find(f => f.id === activeFileId.value) || files.value[0];
    });
    
    // 当前编辑的代码（绑定到活动文件）
    const isFileChanging = ref(false); // 标记是否正在切换文件
    const currentCode = computed({
      get: () => activeFile.value?.content || '',
      set: (value) => {
        if (activeFile.value && !isFileChanging.value) {
          // 只有在不是切换文件时才标记为已修改
          const oldContent = activeFile.value.content;
          activeFile.value.content = value;
          // 只有当内容真正改变时才标记为已修改
          if (oldContent !== value) {
            activeFile.value.modified = true;
          }
        }
      }
    });
    
    // ===== 新建文件对话框 =====
    const newFileDialogVisible = ref(false);
    const newFileForm = ref({
      name: '',
      identifier: '',
      author: '',
      match: ''
    });
    const newFileFormRules = {
      name: [
        { required: true, message: '请输入解析器名称', trigger: 'blur' }
      ],
      identifier: [
        { required: true, message: '请输入标识', trigger: 'blur' }
      ]
    };
    const newFileFormRef = ref(null);
    
    // ===== 加载和认证状态 =====
    const loading = ref(true);
    const loadProgress = ref(0);
    const loadingMessage = ref('初始化...');
    const authChecking = ref(true);
    const authed = ref(false);
    const inputPassword = ref('');
    const authError = ref('');
    const authLoading = ref(false);
    const playgroundEnabled = ref(true); // 演练场是否启用
    
    // ===== 移动端检测 =====
    const isMobile = ref(false);
    
    const testParams = ref({
      shareUrl: 'https://example.com/s/abc',
      pwd: '',
      method: 'parse'
    });
    const testResult = ref(null);
    const testing = ref(false);
    const isDarkMode = ref(false);
    const activeTab = ref('editor');
    const parserList = ref([]);
    const loadingList = ref(false);
    const publishDialogVisible = ref(false);
    const publishing = ref(false);
    const publishForm = ref({
      jsCode: ''
    });
    const helpCollapseActive = ref([]); // 默认折叠
    const consoleLogs = ref([]); // 控制台日志
    
    // ===== 新增状态管理 =====
    // 折叠状态
    const collapsedPanels = ref({
      rightPanel: false,      // 右侧整体面板
      testParams: false,      // 测试参数卡片
      testResult: false,      // 测试结果卡片
      console: false,         // 控制台卡片
      help: true              // 使用说明（默认折叠）
    });
    
    // 主题状态
    const currentTheme = ref('Light'); // Light, Dark, High Contrast
    const themes = [
      { name: 'Light', editor: 'vs', page: 'light', icon: 'Sunny' },
      { name: 'Dark', editor: 'vs-dark', page: 'dark', icon: 'Moon' },
      { name: 'High Contrast', editor: 'hc-black', page: 'dark', icon: 'MostlyCloudy' }
    ];
    
    // 全屏状态
    const isFullscreen = ref(false);
    const playgroundContainer = ref(null);
    
    // 快捷键帮助弹窗
    const shortcutsDialogVisible = ref(false);
    
    // 快捷键数据
    const shortcutsData = [
      { name: '运行测试', keys: ['Ctrl+Enter', 'Cmd+Enter'] },
      { name: '保存代码', keys: ['Ctrl+S', 'Cmd+S'] },
      { name: '格式化代码', keys: ['Shift+Alt+F'] },
      { name: '全屏模式', keys: ['F11'] },
      { name: '清空控制台', keys: ['Ctrl+L', 'Cmd+L'] },
      { name: '重置代码', keys: ['Ctrl+R', 'Cmd+R'] },
      { name: '编辑器缩放', keys: ['Ctrl+滚轮', 'Cmd+滚轮', 'Ctrl+Plus/Minus', 'Cmd+Plus/Minus'] },
      { name: '快捷键帮助', keys: ['Ctrl+/', 'Cmd+/'] }
    ];
    
    // 分栏大小
    const splitSizes = ref([70, 30]);

    // 示例代码模板
    const exampleCode = `// ==UserScript==
// @name         示例解析器
// @type         example_parser
// @displayName  示例网盘
// @description  使用JavaScript实现的示例解析器
// @match        https?://example\.com/s/(?<KEY>\\w+)
// @author       yourname
// @version      1.0.0
// ==/UserScript==

/**
 * 解析单个文件下载链接
 * @param {ShareLinkInfo} shareLinkInfo - 分享链接信息
 * @param {JsHttpClient} http - HTTP客户端
 * @param {JsLogger} logger - 日志对象
 * @returns {string} 下载链接
 */
function parse(shareLinkInfo, http, logger) {
    var url = shareLinkInfo.getShareUrl();
    logger.info("开始解析: " + url);
    
    var response = http.get('https://example.com');
    if (!response.isSuccess()) {
        throw new Error("请求失败: " + response.statusCode());
    }
    
    var html = response.body();
    // 这里添加你的解析逻辑
    // 例如：使用正则表达式提取下载链接
    
    return "https://example.com/download/file.zip";
}

/**
 * 解析文件列表（可选）
 * @param {ShareLinkInfo} shareLinkInfo - 分享链接信息
 * @param {JsHttpClient} http - HTTP客户端
 * @param {JsLogger} logger - 日志对象
 * @returns {Array} 文件信息数组
 */
function parseFileList(shareLinkInfo, http, logger) {
    var dirId = shareLinkInfo.getOtherParam("dirId") || "0";
    logger.info("解析文件列表，目录ID: " + dirId);
    
    // 这里添加你的文件列表解析逻辑
    var fileList = [];
    
    return fileList;
}

/**
 * 根据文件ID获取下载链接（可选）
 * @param {ShareLinkInfo} shareLinkInfo - 分享链接信息
 * @param {JsHttpClient} http - HTTP客户端
 * @param {JsLogger} logger - 日志对象
 * @returns {string} 下载链接
 */
function parseById(shareLinkInfo, http, logger) {
    var paramJson = shareLinkInfo.getOtherParam("paramJson");
    var fileId = paramJson.fileId;
    logger.info("根据ID解析: " + fileId);
    
    // 这里添加你的按ID解析逻辑
    
    return "https://example.com/download?id=" + fileId;
}`;

    // 编辑器主题
    const editorTheme = computed(() => {
      // 根据当前主题名称直接判断，而不是依赖 isDarkMode
      const theme = themes.find(t => t.name === currentTheme.value);
      if (theme) {
        return theme.editor;
      }
      // 如果没有找到主题，回退到基于 isDarkMode 的判断
      return isDarkMode.value ? 'vs-dark' : 'vs';
    });
    
    // 计算属性：是否需要显示密码输入界面
    const shouldShowAuthUI = computed(() => {
      return !loading.value && !authChecking.value && !authed.value && playgroundEnabled.value;
    });

    // 编辑器配置
    const wordWrapEnabled = ref(true);
    const editorOptions = computed(() => {
      const baseOptions = {
        minimap: { enabled: !isMobile.value }, // 移动端禁用 minimap
        scrollBeyondLastLine: false,
        wordWrap: wordWrapEnabled.value ? 'on' : 'off',
        lineNumbers: 'on',
        lineNumbersMinChars: isMobile.value ? 3 : 5, // 移动端行号最多显示3位
        formatOnPaste: true,
        formatOnType: true,
        tabSize: 2,
        // 启用缩放功能
        mouseWheelZoom: true, // PC端：Ctrl/Cmd + 鼠标滚轮缩放
        fontSize: 14, // 默认字体大小
        quickSuggestions: true,
        // 移动端支持触摸缩放
        ...(isMobile.value ? {
          // 移动端特殊配置
        } : {})
      };
      return baseOptions;
    });
    
    // ===== 移动端检测 =====
    const updateIsMobile = () => {
      const wasMobile = isMobile.value;
      isMobile.value = window.innerWidth <= 768;
      // 如果是移动端，调整分栏大小，让测试面板有更多空间
      if (isMobile.value && !wasMobile) {
        splitSizes.value = [50, 50]; // 移动端：编辑器50%，测试面板50%
      } else if (!isMobile.value && wasMobile) {
        splitSizes.value = [70, 30]; // 桌面端：编辑器70%，测试面板30%
      }
    };
    
    // ===== 进度设置函数 =====
    const setProgress = (progress, message = '') => {
      if (progress > loadProgress.value) {
        loadProgress.value = progress;
      }
      if (message) {
        loadingMessage.value = message;
      }
    };
    
    // ===== 认证相关函数 =====
    const checkAuthStatus = async () => {
      try {
        const res = await playgroundApi.getStatus();
        if (res.code === 200 && res.data) {
          // 检查是否启用
          playgroundEnabled.value = res.data.enabled === true;
          
          if (!playgroundEnabled.value) {
            authChecking.value = false;
            return false;
          }
          
          // 先检查localStorage中是否有保存的登录信息
          const savedAuth = localStorage.getItem('playground_authed');
          const authTime = localStorage.getItem('playground_auth_time');
          
          // 如果30天内登录过，直接认为已认证（实际认证状态由后端session决定）
          if (savedAuth === 'true' && authTime) {
            const daysSinceAuth = (Date.now() - parseInt(authTime)) / (1000 * 60 * 60 * 24);
            if (daysSinceAuth < 30) {
              // 先设置为已认证，然后验证后端session
              authed.value = true;
            }
          }
          
          const isAuthed = res.data.authed || res.data.public;
          authed.value = isAuthed;
          
          // 如果后端认证已失效，清除localStorage中的认证信息
          if (!isAuthed && savedAuth === 'true') {
            localStorage.removeItem('playground_authed');
            localStorage.removeItem('playground_auth_time');
            localStorage.removeItem('playground_token');
          }
          
          return isAuthed;
        }
        playgroundEnabled.value = false;
        return false;
      } catch (error) {
        console.error('检查认证状态失败:', error);
        // 如果错误信息包含"已禁用"，则设置启用状态为false
        if (error.message && error.message.includes('已禁用')) {
          playgroundEnabled.value = false;
        } else {
          ElMessage.error('检查访问权限失败: ' + error.message);
        }
        return false;
      } finally {
        authChecking.value = false;
      }
    };
    
    // 返回首页
    const goHome = () => {
      router.push('/');
    };
    
    // 新窗口打开首页
    const goHomeInNewWindow = () => {
      window.open('/', '_blank', 'noopener,noreferrer');
    };
    
    // 检查是否有未保存的文件
    const hasUnsavedFiles = computed(() => {
      return files.value.some(f => f.modified);
    });
    
    // 页面关闭/刷新前的提示
    const handleBeforeUnload = (e) => {
      if (hasUnsavedFiles.value) {
        e.preventDefault();
        e.returnValue = '您有未保存的文件，确定要离开吗？';
        return e.returnValue;
      }
    };
    
    const submitPassword = async () => {
      if (!inputPassword.value.trim()) {
        authError.value = '请输入密码';
        return;
      }
      
      authError.value = '';
      authLoading.value = true;
      
      try {
        const res = await playgroundApi.login(inputPassword.value);
        if (res.code === 200 || res.success) {
          authed.value = true;
          // 保存登录信息到localStorage，避免每次都需要登录
          localStorage.setItem('playground_authed', 'true');
          localStorage.setItem('playground_auth_time', Date.now().toString());
          ElMessage.success('登录成功');
          await initPlayground();
        } else {
          authError.value = res.msg || res.message || '密码错误';
        }
      } catch (error) {
        authError.value = error.message || '登录失败，请重试';
      } finally {
        authLoading.value = false;
      }
    };
    
    // ===== Playground 初始化 =====
    const initPlayground = async () => {
      loading.value = true;
      loadProgress.value = 0;
      
      try {
        setProgress(10, '初始化Vue组件...');
        await nextTick();
        
        setProgress(20, '加载配置和本地数据...');
        
        // 加载保存的文件列表
        loadAllFilesFromStorage();
        
        // 如果没有文件，加载默认代码
        if (files.value.length === 0 || !files.value[0].content) {
          const saved = localStorage.getItem('playground_code');
          if (saved) {
            if (files.value.length === 0) {
              files.value.push({ id: 'file1', name: '文件1.js', content: saved, modified: false });
            } else {
              files.value[0].content = saved;
            }
          } else {
            if (files.value.length === 0) {
              files.value.push({ id: 'file1', name: '文件1.js', content: exampleCode, modified: false });
            } else {
              files.value[0].content = exampleCode;
            }
            testParams.value.shareUrl = 'https://example.com/s/abc';
            testParams.value.pwd = '';
            testParams.value.method = 'parse';
          }
        }
        
        // 更新第一个文件的名称（从代码中提取）
        if (files.value.length > 0 && files.value[0].id === 'file1') {
          updateFileNameFromCode(files.value[0]);
        }
        
        // 先加载保存的主题（在编辑器初始化之前）
        const savedTheme = localStorage.getItem('playground_theme');
        if (savedTheme) {
          currentTheme.value = savedTheme;
          const theme = themes.find(t => t.name === savedTheme);
          if (theme) {
            // 同步更新 isDarkMode
            isDarkMode.value = theme.page === 'dark';
            
            await nextTick();
            const html = document.documentElement;
            const body = document.body;
            if (html && body && html.classList && body.classList) {
              if (theme.page === 'dark') {
                html.classList.add('dark');
                body.classList.add('dark-theme');
                body.style.backgroundColor = '#0a0a0a';
              } else {
                html.classList.remove('dark');
                body.classList.remove('dark-theme');
                body.style.backgroundColor = '#f0f2f5';
              }
            }
          }
        }
        
        
        setProgress(50, '初始化Monaco Editor类型定义...');
        await initMonacoTypes();
        
        setProgress(80, '加载完成...');
        
        // 加载保存的折叠状态
        const savedCollapsed = localStorage.getItem('playground_collapsed_panels');
        if (savedCollapsed) {
          try {
            collapsedPanels.value = JSON.parse(savedCollapsed);
          } catch (e) {
            console.warn('加载折叠状态失败', e);
          }
        }
        
        setProgress(100, '初始化完成！');
        await new Promise(resolve => setTimeout(resolve, 300));
        
      } catch (error) {
        console.error('初始化失败:', error);
        ElMessage.error('初始化失败: ' + error.message);
      } finally {
        loading.value = false;
      }
    };

    // 初始化Monaco Editor类型定义
    const initMonacoTypes = async () => {
      try {
        // 动态导入loader
        const loaderModule = await import('@monaco-editor/loader');
        const loader = loaderModule.default || loaderModule.loader || loaderModule;
        
        if (!loader || typeof loader.init !== 'function') {
          console.error('Monaco Editor loader加载失败');
          return;
        }
        
        // 配置Monaco Editor使用本地打包的文件，而不是CDN
        if (loader.config) {
          const vsPath = process.env.NODE_ENV === 'production' 
            ? './js/vs'  // 生产环境使用相对路径
            : '/js/vs';  // 开发环境使用绝对路径
          
          loader.config({ 
            paths: { 
              vs: vsPath
            }
          });
        }
        
        const monaco = await loader.init();
        if (monaco) {
          await configureMonacoTypes(monaco);
          await loadTypesFromApi(monaco);
        }
      } catch (error) {
        console.error('初始化Monaco类型定义失败:', error);
      }
    };

    // 代码变化处理
    const onCodeChange = (value) => {
      currentCode.value = value;
      // 更新第一个文件的名称（如果代码中包含@name）
      if (activeFile.value && activeFile.value.id === 'file1') {
        updateFileNameFromCode(activeFile.value);
      }
      // 保存到localStorage（保存所有文件）
      saveAllFilesToStorage();
    };
    
    // 保存所有文件到localStorage
    const saveAllFilesToStorage = () => {
      const filesData = files.value.map(f => ({
        id: f.id,
        name: f.name,
        content: f.content
      }));
      localStorage.setItem('playground_files', JSON.stringify(filesData));
      localStorage.setItem('playground_active_file', activeFileId.value);
    };
    
    // 从localStorage加载所有文件
    const loadAllFilesFromStorage = () => {
      const savedFiles = localStorage.getItem('playground_files');
      if (savedFiles) {
        try {
          const filesData = JSON.parse(savedFiles);
          files.value = filesData.map(f => ({
            ...f,
            modified: false
          }));
          const savedActiveFile = localStorage.getItem('playground_active_file');
          if (savedActiveFile && files.value.find(f => f.id === savedActiveFile)) {
            activeFileId.value = savedActiveFile;
          }
        } catch (e) {
          console.warn('加载文件列表失败', e);
        }
      }
    };
    
    // 文件切换处理
    const handleFileChange = (fileId) => {
      // 标记正在切换文件，防止触发修改标记
      isFileChanging.value = true;
      activeFileId.value = fileId;
      saveAllFilesToStorage();
      // 等待编辑器更新
      nextTick(() => {
        if (editorRef.value && editorRef.value.getEditor) {
          const editor = editorRef.value.getEditor();
          if (editor) {
            editor.focus();
          }
        }
        // 切换完成后，取消标记
        setTimeout(() => {
          isFileChanging.value = false;
        }, 100);
      });
    };
    
    // 删除文件
    const removeFile = (fileId) => {
      if (files.value.length <= 1) {
        ElMessage.warning('至少需要保留一个文件');
        return;
      }
      const index = files.value.findIndex(f => f.id === fileId);
      if (index !== -1) {
        files.value.splice(index, 1);
        // 如果删除的是当前活动文件，切换到第一个文件
        if (activeFileId.value === fileId) {
          activeFileId.value = files.value[0].id;
        }
        saveAllFilesToStorage();
      }
    };
    
    // 显示新建文件对话框
    const showNewFileDialog = () => {
      newFileForm.value = {
        name: '',
        identifier: '',
        author: '',
        match: ''
      };
      newFileDialogVisible.value = true;
    };
    
    // 生成模板代码
    const generateTemplate = (name, identifier, author, match) => {
      const type = identifier.toLowerCase().replace(/[^a-z0-9]/g, '_');
      const displayName = name;
      const description = `使用JavaScript实现的${name}解析器`;
      
      return `// ==UserScript==
// @name         ${name}
// @type         ${type}
// @displayName  ${displayName}
// @description  ${description}
// @match        ${match || 'https?://example.com/s/(?<KEY>\\w+)'}
// @author       ${author || 'yourname'}
// @version      1.0.0
// ==/UserScript==

/**
 * 解析单个文件下载链接
 * @param {ShareLinkInfo} shareLinkInfo - 分享链接信息
 * @param {JsHttpClient} http - HTTP客户端
 * @param {JsLogger} logger - 日志对象
 * @returns {string} 下载链接
 */
function parse(shareLinkInfo, http, logger) {
    var url = shareLinkInfo.getShareUrl();
    logger.info("开始解析: " + url);
    
    var response = http.get(url);
    if (!response.isSuccess()) {
        throw new Error("请求失败: " + response.statusCode());
    }
    
    var html = response.body();
    // 这里添加你的解析逻辑
    // 例如：使用正则表达式提取下载链接
    
    return "https://example.com/download/file.zip";
}

/**
 * 解析文件列表（可选）
 * @param {ShareLinkInfo} shareLinkInfo - 分享链接信息
 * @param {JsHttpClient} http - HTTP客户端
 * @param {JsLogger} logger - 日志对象
 * @returns {Array} 文件信息数组
 */
function parseFileList(shareLinkInfo, http, logger) {
    var dirId = shareLinkInfo.getOtherParam("dirId") || "0";
    logger.info("解析文件列表，目录ID: " + dirId);
    
    // 这里添加你的文件列表解析逻辑
    var fileList = [];
    
    return fileList;
}`;
    };
    
    // 创建新文件
    const createNewFile = async () => {
      if (!newFileFormRef.value) return;
      
      await newFileFormRef.value.validate((valid) => {
        if (!valid) return;
        
        // 使用解析器名称作为文件名
        const fileName = newFileForm.value.name.endsWith('.js') 
          ? newFileForm.value.name 
          : newFileForm.value.name + '.js';
        
        // 检查文件名是否已存在
        if (files.value.some(f => f.name === fileName)) {
          ElMessage.warning('文件名已存在，请使用其他名称');
          return;
        }
        
        // 生成模板代码
        const template = generateTemplate(
          newFileForm.value.name,
          newFileForm.value.identifier,
          newFileForm.value.author,
          newFileForm.value.match
        );
        
        // 创建新文件
        fileIdCounter.value++;
        const newFile = {
          id: 'file' + fileIdCounter.value,
          name: fileName,
          content: template,
          modified: false
        };
        
        files.value.push(newFile);
        activeFileId.value = newFile.id;
        newFileDialogVisible.value = false;
        saveAllFilesToStorage();
        
        ElMessage.success('文件创建成功');
        
        // 等待编辑器更新后聚焦
        nextTick(() => {
          if (editorRef.value && editorRef.value.getEditor) {
            const editor = editorRef.value.getEditor();
            if (editor) {
              editor.focus();
            }
          }
        });
      });
    };
    
    // IDE功能：复制全部
    const copyAll = async () => {
      try {
        await navigator.clipboard.writeText(currentCode.value);
        ElMessage.success('已复制全部内容到剪贴板');
      } catch (error) {
        ElMessage.error('复制失败: ' + error.message);
      }
    };
    
    // IDE功能：全选
    const selectAll = () => {
      if (editorRef.value && editorRef.value.getEditor) {
        const editor = editorRef.value.getEditor();
        if (editor) {
          editor.setSelection(editor.getModel().getFullModelRange());
          editor.focus();
        }
      }
    };
    
    // IDE功能：切换自动换行
    const toggleWordWrap = () => {
      wordWrapEnabled.value = !wordWrapEnabled.value;
      // 更新编辑器选项
      if (editorRef.value && editorRef.value.getEditor) {
        const editor = editorRef.value.getEditor();
        if (editor) {
          editor.updateOptions({ wordWrap: wordWrapEnabled.value ? 'on' : 'off' });
        }
      }
      ElMessage.success(wordWrapEnabled.value ? '已开启自动换行' : '已关闭自动换行');
    };
    
    // IDE功能：导出当前文件
    const exportCurrentFile = () => {
      if (!activeFile.value || !activeFile.value.content) {
        ElMessage.warning('当前文件为空，无法导出');
        return;
      }
      
      try {
        const blob = new Blob([activeFile.value.content], { type: 'text/javascript;charset=utf-8' });
        const url = URL.createObjectURL(blob);
        const link = document.createElement('a');
        link.href = url;
        link.download = activeFile.value.name;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);
        URL.revokeObjectURL(url);
        ElMessage.success('文件导出成功');
      } catch (error) {
        ElMessage.error('导出失败: ' + error.message);
      }
    };
    
    // IDE功能：撤销
    const undo = () => {
      if (editorRef.value && editorRef.value.getEditor) {
        const editor = editorRef.value.getEditor();
        if (editor) {
          editor.trigger('keyboard', 'undo', null);
          editor.focus();
        }
      }
    };
    
    // IDE功能：重做
    const redo = () => {
      if (editorRef.value && editorRef.value.getEditor) {
        const editor = editorRef.value.getEditor();
        if (editor) {
          editor.trigger('keyboard', 'redo', null);
          editor.focus();
        }
      }
    };
    
    // 从代码中提取解析器名称
    const extractParserName = (code) => {
      if (!code) return null;
      const match = code.match(/@name\s+([^\r\n]+)/);
      if (match && match[1]) {
        return match[1].trim();
      }
      return null;
    };
    
    // 更新文件名称（从代码中提取）
    const updateFileNameFromCode = (file) => {
      if (!file || file.id !== 'file1') return; // 只更新第一个文件
      const parserName = extractParserName(file.content);
      if (parserName) {
        const newName = parserName.endsWith('.js') ? parserName : parserName + '.js';
        if (file.name !== newName) {
          file.name = newName;
          saveAllFilesToStorage();
        }
      }
    };

    // 加载示例代码
    const loadTemplate = () => {
      if (activeFile.value) {
        activeFile.value.content = exampleCode;
        activeFile.value.modified = true;
      }
      // 重置测试参数为示例链接
      testParams.value.shareUrl = 'https://example.com/s/abc';
      testParams.value.pwd = '';
      testParams.value.method = 'parse';
      // 清空测试结果
      testResult.value = null;
      consoleLogs.value = [];
      ElMessage.success('已加载JavaScript示例代码');
    };

    // 格式化代码
    const formatCode = () => {
      if (editorRef.value && editorRef.value.getEditor) {
        const editor = editorRef.value.getEditor();
        if (editor) {
          editor.getAction('editor.action.formatDocument').run();
        }
      }
    };

    // 保存代码
    const saveCode = () => {
      if (activeFile.value) {
        activeFile.value.modified = false;
        saveAllFilesToStorage();
        ElMessage.success('代码已保存');
      }
    };

    // 加载代码（已废弃，使用多文件管理）
    const loadCode = () => {
      loadAllFilesFromStorage();
      ElMessage.success('代码已加载');
    };

    // 清空代码
    const clearCode = () => {
      if (activeFile.value) {
        activeFile.value.content = '';
        activeFile.value.modified = true;
      }
      testResult.value = null;
    };

    // 语言切换处理
    // 执行测试
    const executeTest = async () => {
      const codeToTest = currentCode.value;
      if (!codeToTest.trim()) {
        ElMessage.warning('请先输入JavaScript代码');
        return;
      }

      if (!testParams.value.shareUrl.trim()) {
        ElMessage.warning('请输入分享链接');
        return;
      }
      
      // 检查代码中是否包含潜在的危险模式
      const dangerousPatterns = [
        { pattern: /while\s*\(\s*true\s*\)/gi, message: '检测到 while(true) 无限循环' },
        { pattern: /for\s*\(\s*;\s*;\s*\)/gi, message: '检测到 for(;;) 无限循环' },
        { pattern: /for\s*\(\s*var\s+\w+\s*=\s*\d+\s*;\s*true\s*;/gi, message: '检测到可能的无限循环' }
      ];
      
      for (const { pattern, message } of dangerousPatterns) {
        if (pattern.test(codeToTest)) {
          const confirmed = await ElMessageBox.confirm(
            `⚠️ ${message}\n\n这可能导致脚本无法停止并占用服务器资源。\n\n建议修改代码，添加合理的循环退出条件。\n\n确定要继续执行吗？`,
            '危险代码警告',
            {
              confirmButtonText: '我知道风险，继续执行',
              cancelButtonText: '取消',
              type: 'warning',
              dangerouslyUseHTMLString: true
            }
          ).catch(() => false);
          
          if (!confirmed) {
            return;
          }
          break;
        }
      }

      testing.value = true;
      testResult.value = null;
      consoleLogs.value = []; // 清空控制台

      try {
        const result = await playgroundApi.testScript(
          codeToTest,  // 使用当前活动文件的代码
          testParams.value.shareUrl,
          testParams.value.pwd,
          testParams.value.method
        );
        
        console.log('测试结果:', result);
        testResult.value = result;
        
        // 将日志添加到控制台
        if (result && result.logs && Array.isArray(result.logs) && result.logs.length > 0) {
          consoleLogs.value = [...result.logs];
        } else if (result && result.success) {
          // 即使没有日志，也显示一个成功信息
          consoleLogs.value = [{
            level: 'INFO',
            message: '执行成功',
            timestamp: Date.now()
          }];
        }
      } catch (error) {
        console.error('执行测试失败:', error);
        testResult.value = {
          success: false,
          error: error.message || '执行失败',
          logs: [],
          executionTime: 0
        };
        // 添加错误日志到控制台
        consoleLogs.value = [{
          level: 'ERROR',
          message: error.message || '执行失败',
          timestamp: Date.now()
        }];
      } finally {
        testing.value = false;
      }
    };

    // 清空控制台日志
    const clearConsoleLogs = () => {
      consoleLogs.value = [];
    };

    // 格式化时间
    const formatTime = (timestamp) => {
      const date = new Date(timestamp);
      return date.toLocaleTimeString('zh-CN', {
        hour12: false,
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        fractionalSecondDigits: 3
      });
    };

    // 格式化日期时间
    const formatDateTime = (dateTimeStr) => {
      if (!dateTimeStr) return '';
      const date = new Date(dateTimeStr);
      return date.toLocaleString('zh-CN');
    };

    // 加载解析器列表
    const loadParserList = async () => {
      loadingList.value = true;
      try {
        const result = await playgroundApi.getParserList();
        console.log('获取解析器列表响应:', result);
        // 检查响应格式
        if (result.code === 200 || result.success) {
          console.log('列表数据:', result.data);
          parserList.value = result.data || [];
        } else if (result.data && Array.isArray(result.data)) {
          // 如果data直接是数组
          parserList.value = result.data;
        } else {
          console.error('无法解析列表数据格式:', result);
          ElMessage.error(result.msg || result.error || '加载列表失败');
        }
      } catch (error) {
        console.error('加载列表错误:', error);
        ElMessage.error(error.message || '加载列表失败');
      } finally {
        loadingList.value = false;
      }
    };

    // 发布解析器
    const publishParser = () => {
      const codeToPublish = currentCode.value;
      if (!codeToPublish.trim()) {
        ElMessage.warning('请先编写JavaScript代码');
        return;
      }
      publishForm.value.jsCode = codeToPublish;
      publishDialogVisible.value = true;
    };

    // 确认发布
    const confirmPublish = async () => {
      publishing.value = true;
      try {
        const codeToPublish = currentCode.value;
        const result = await playgroundApi.saveParser(codeToPublish);
        console.log('保存解析器响应:', result);
        // 检查响应格式
        if (result.code === 200 || result.success) {
          // 从响应或代码中提取type信息
          let parserType = '';
          try {
            const typeMatch = codeToPublish.match(/@type\s+(\w+)/);
            parserType = typeMatch ? typeMatch[1] : '';
          } catch (e) {
            console.warn('无法提取type', e);
          }
          
          // 构建API调用示例
          const baseUrl = window.location.origin;
          const exampleUrl = 'https://lanzoui.com/i7Aq12ab3cd';
          
          const apiExamples = `
<div style="text-align: left; padding: 0 20px;">
  <h3>✅ 发布成功！</h3>
  <p>解析器类型: <code>${parserType || '未知'}</code></p>
  
  <h4>📡 API调用示例：</h4>
  
  <div style="margin: 10px 0;">
    <strong>1. 302重定向（直接下载）</strong>
    <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">${baseUrl}/parser?url=${encodeURIComponent(exampleUrl)}</pre>
    <p style="color: #666; font-size: 12px;">浏览器访问该链接会自动跳转到下载地址</p>
  </div>
  
  <div style="margin: 10px 0;">
    <strong>2. JSON响应（获取解析结果）</strong>
    <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}</pre>
    <p style="color: #666; font-size: 12px;">返回JSON格式的解析结果，包含下载链接等信息</p>
  </div>
  
  <div style="margin: 10px 0;">
    <strong>3. 带密码</strong>
    <pre style="background: #f5f5f5; padding: 10px; border-radius: 4px; overflow-x: auto;">${baseUrl}/parser?url=${encodeURIComponent(exampleUrl)}&pwd=1234</pre>
  </div>
  
  <h4>🔧 curl命令示例：</h4>
  <pre style="background: #2d2d2d; color: #fff; padding: 10px; border-radius: 4px; overflow-x: auto;"># 302重定向
curl -L "${baseUrl}/parser?url=${encodeURIComponent(exampleUrl)}"

# JSON响应
curl "${baseUrl}/json/parser?url=${encodeURIComponent(exampleUrl)}"</pre>
  
  <p style="margin-top: 15px; color: #409eff;">
    💡 提示：将示例链接替换为实际的分享链接即可使用
  </p>
</div>`;
          
          ElMessageBox.alert(apiExamples, '发布成功', {
            dangerouslyUseHTMLString: true,
            confirmButtonText: '知道了',
            customClass: 'api-example-dialog'
          });
          
          publishDialogVisible.value = false;
          // 切换到列表标签页并刷新
          activeTab.value = 'list';
          await loadParserList();
        } else {
          console.error('保存失败响应:', result);
          ElMessage.error(result.msg || result.error || '发布失败');
        }
      } catch (error) {
        console.error('发布失败错误:', error);
        ElMessage.error(error.message || '发布失败');
      } finally {
        publishing.value = false;
      }
    };

    // 加载解析器到编辑器（添加到新的文件tab标签）
    const loadParserToEditor = async (parser) => {
      try {
        const result = await playgroundApi.getParserById(parser.id);
        if (result.code === 200 && result.data) {
          // 从代码中提取文件名
          const code = result.data.jsCode;
          let fileName = parser.name || '解析器.js';
          
          // 尝试从@name提取文件名
          const nameMatch = code.match(/@name\s+([^\r\n]+)/);
          if (nameMatch && nameMatch[1]) {
            const parserName = nameMatch[1].trim();
            fileName = parserName.endsWith('.js') ? parserName : parserName + '.js';
          }
          
          // 检查文件名是否已存在，如果存在则添加序号
          let finalFileName = fileName;
          let counter = 1;
          while (files.value.some(f => f.name === finalFileName)) {
            const nameWithoutExt = fileName.replace(/\.js$/, '');
            finalFileName = `${nameWithoutExt}_${counter}.js`;
            counter++;
          }
          
          // 创建新文件
          fileIdCounter.value++;
          const newFile = {
            id: 'file' + fileIdCounter.value,
            name: finalFileName,
            content: code,
            modified: false
          };
          
          files.value.push(newFile);
          activeFileId.value = newFile.id;
          activeTab.value = 'editor';
          saveAllFilesToStorage();
          
          ElMessage.success('已添加到新文件标签');
          
          // 等待编辑器更新后聚焦
          nextTick(() => {
            if (editorRef.value && editorRef.value.getEditor) {
              const editor = editorRef.value.getEditor();
              if (editor) {
                editor.focus();
              }
            }
          });
        } else {
          ElMessage.error('加载失败');
        }
      } catch (error) {
        ElMessage.error(error.message || '加载失败');
      }
    };

    // 删除解析器
    const deleteParser = async (id) => {
      try {
        await ElMessageBox.confirm('确定要删除这个解析器吗？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        });

        const result = await playgroundApi.deleteParser(id);
        if (result.code === 200) {
          ElMessage.success('删除成功');
          await loadParserList();
        } else {
          ElMessage.error(result.msg || '删除失败');
        }
      } catch (error) {
        if (error !== 'cancel') {
          ElMessage.error(error.message || '删除失败');
        }
      }
    };

    // 标签页切换
    const handleTabChange = (tabName) => {
      if (tabName === 'list') {
        loadParserList();
      }
    };

    // ===== 主题切换功能 =====
    const changeTheme = (themeName) => {
      currentTheme.value = themeName;
      const theme = themes.find(t => t.name === themeName);
      if (theme) {
        // 同步更新 isDarkMode
        isDarkMode.value = theme.page === 'dark';
        
        // 切换页面主题
        const html = document.documentElement;
        const body = document.body;
        
        if (html && body && html.classList && body.classList) {
          if (theme.page === 'dark') {
            html.classList.add('dark');
            body.classList.add('dark-theme');
            // 设置背景色
            body.style.backgroundColor = '#0a0a0a';
          } else {
            html.classList.remove('dark');
            body.classList.remove('dark-theme');
            // 设置背景色
            body.style.backgroundColor = '#f0f2f5';
          }
        }
        
        // 编辑器主题会通过computed自动更新
        localStorage.setItem('playground_theme', themeName);
        // 强制更新splitpanes分隔线样式
        updateSplitpanesStyle();
        ElMessage.success(`已切换到${themeName}主题`);
      }
    };
    
    const toggleTheme = () => {
      const currentIndex = themes.findIndex(t => t.name === currentTheme.value);
      const nextIndex = (currentIndex + 1) % themes.length;
      changeTheme(themes[nextIndex].name);
    };
    
    // ===== 折叠/展开功能 =====
    const togglePanel = (panelName) => {
      collapsedPanels.value[panelName] = !collapsedPanels.value[panelName];
      localStorage.setItem('playground_collapsed_panels', JSON.stringify(collapsedPanels.value));
    };
    
    const toggleRightPanel = () => {
      collapsedPanels.value.rightPanel = !collapsedPanels.value.rightPanel;
      localStorage.setItem('playground_collapsed_panels', JSON.stringify(collapsedPanels.value));
    };
    
    // 处理分栏大小调整
    const handleResize = (panes) => {
      if (panes && Array.isArray(panes)) {
        splitSizes.value = panes.map(p => p.size || 50);
      }
      // 调整大小后更新分隔线样式
      updateSplitpanesStyle();
    };
    
    // ===== 全屏功能 =====
    const { isFullscreen: isDocumentFullscreen, toggle: toggleDocumentFullscreen } = useFullscreen();
    
    const toggleFullscreen = () => {
      isFullscreen.value = !isFullscreen.value;
      toggleDocumentFullscreen();
    };
    
    // ===== 快捷键帮助 =====
    const showShortcutsHelp = () => {
      shortcutsDialogVisible.value = true;
    };
    
    // ===== 快捷键系统 =====
    const keys = useMagicKeys();
    const ctrlEnter = keys['Ctrl+Enter'];
    const cmdEnter = keys['Meta+Enter'];
    const ctrlS = keys['Ctrl+S'];
    const cmdS = keys['Meta+S'];
    const shiftAltF = keys['Shift+Alt+F'];
    const f11 = keys['F11'];
    const ctrlL = keys['Ctrl+L'];
    const cmdL = keys['Meta+L'];
    const ctrlR = keys['Ctrl+R'];
    const cmdR = keys['Meta+R'];
    const ctrlSlash = keys['Ctrl+/'];
    const cmdSlash = keys['Meta+/'];
    
    // 执行测试 - Ctrl/Cmd + Enter
    watch([ctrlEnter, cmdEnter], ([ctrl, cmd]) => {
      if (ctrl || cmd) {
        executeTest();
      }
    });
    
    // 保存代码 - Ctrl/Cmd + S
    watch([ctrlS, cmdS], ([ctrl, cmd]) => {
      if (ctrl || cmd) {
        saveCode();
      }
    });
    
    // 格式化代码 - Shift + Alt + F
    watch(shiftAltF, (pressed) => {
      if (pressed) {
        formatCode();
      }
    });
    
    // 全屏模式 - F11
    watch(f11, (pressed) => {
      if (pressed) {
        toggleFullscreen();
      }
    });
    
    // 清空控制台 - Ctrl/Cmd + L
    watch([ctrlL, cmdL], ([ctrl, cmd]) => {
      if (ctrl || cmd) {
        clearConsoleLogs();
      }
    });
    
    // 重置代码 - Ctrl/Cmd + R
    watch([ctrlR, cmdR], ([ctrl, cmd]) => {
      if (ctrl || cmd) {
        loadTemplate();
      }
    });
    
    // 快捷键帮助 - Ctrl/Cmd + /
    watch([ctrlSlash, cmdSlash], ([ctrl, cmd]) => {
      if (ctrl || cmd) {
        showShortcutsHelp();
      }
    });
    
    // 阻止浏览器默认快捷键
    useEventListener('keydown', (e) => {
      // 阻止 Ctrl/Cmd + S 默认保存
      if ((e.ctrlKey || e.metaKey) && e.key === 's') {
        e.preventDefault();
      }
      // 阻止 Ctrl/Cmd + R 默认刷新
      if ((e.ctrlKey || e.metaKey) && e.key === 'r') {
        e.preventDefault();
      }
      // 阻止 F11 默认全屏
      if (e.key === 'F11') {
        e.preventDefault();
      }
    });
    
    // 检查暗色主题
    const checkDarkMode = () => {
      try {
        const html = document.documentElement;
        const body = document.body;
        if (!html || !body) {
          return; // DOM未准备好，直接返回
        }
        
        if (html.classList) {
          isDarkMode.value = html.classList.contains('dark') || 
                            html.getAttribute('data-theme') === 'dark';
          // 强制更新splitpanes分隔线样式
          updateSplitpanesStyle();
        }
      } catch (error) {
        console.warn('检查暗色主题失败:', error);
      }
    };
    
    // 强制更新splitpanes分隔线样式
    const updateSplitpanesStyle = () => {
      setTimeout(() => {
        try {
          const html = document.documentElement;
          const body = document.body;
          if (!html || !body) {
            return; // DOM未准备好，直接返回
          }
          
          const splitters = document.querySelectorAll('.splitpanes__splitter');
          const isDark = html.classList?.contains('dark') || 
                        body.classList?.contains('dark-theme');
          
          splitters.forEach(splitter => {
            if (splitter) {
              if (isDark) {
                splitter.style.setProperty('background-color', 'rgba(255, 255, 255, 0.08)', 'important');
                splitter.style.setProperty('background', 'rgba(255, 255, 255, 0.08)', 'important');
              } else {
                splitter.style.removeProperty('background-color');
                splitter.style.removeProperty('background');
              }
            }
          });
        } catch (error) {
          console.warn('更新splitpanes样式失败:', error);
        }
      }, 100);
    };

    onMounted(async () => {
      // 初始化移动端检测
      updateIsMobile();
      window.addEventListener('resize', updateIsMobile);
      
      // 添加页面关闭/刷新前的提示
      window.addEventListener('beforeunload', handleBeforeUnload);
      
      // 检查认证状态
      const isAuthed = await checkAuthStatus();
      
      // 如果已认证，初始化playground
      if (isAuthed) {
        await initPlayground();
      } else {
        // 未认证，停止加载动画，显示密码输入
        loading.value = false;
      }
      
      await nextTick();
      checkDarkMode();

      // 监听主题变化
      const html = document.documentElement;
      if (html && html.classList) {
        try {
          const observer = new MutationObserver(() => {
            checkDarkMode();
          });
          observer.observe(html, {
            attributes: true,
            attributeFilter: ['class', 'data-theme']
          });
        } catch (error) {
          console.warn('创建主题监听器失败:', error);
        }
      }
      
      // 初始化splitpanes样式
      updateSplitpanesStyle();
    });
    
    onUnmounted(() => {
      window.removeEventListener('resize', updateIsMobile);
      // 移除页面关闭/刷新前的提示
      window.removeEventListener('beforeunload', handleBeforeUnload);
    });

    return {
      LANGUAGE,
      editorRef,
      jsCode,
      currentCode,
      testParams,
      testResult,
      testing,
      isDarkMode,
      editorTheme,
      shouldShowAuthUI,
      editorOptions,
      // 多文件管理
      files,
      activeFileId,
      activeFile,
      handleFileChange,
      removeFile,
      // 新建文件
      newFileDialogVisible,
      newFileForm,
      newFileFormRef,
      newFileFormRules,
      showNewFileDialog,
      createNewFile,
      // IDE功能
      copyAll,
      selectAll,
      toggleWordWrap,
      wordWrapEnabled,
      exportCurrentFile,
      undo,
      redo,
      // 加载和认证
      loading,
      loadProgress,
      loadingMessage,
      authChecking,
      authed,
      inputPassword,
      authError,
      authLoading,
      playgroundEnabled,
      checkAuthStatus,
      submitPassword,
      goHome,
      goHomeInNewWindow,
      // 移动端
      isMobile,
      updateIsMobile,
      onCodeChange,
      loadTemplate,
      formatCode,
      saveCode,
      loadCode,
      clearCode,
      executeTest,
      formatTime,
      formatDateTime,
      activeTab,
      parserList,
      loadingList,
      publishDialogVisible,
      publishing,
      publishForm,
      loadParserList,
      publishParser,
      confirmPublish,
      loadParserToEditor,
      deleteParser,
      handleTabChange,
      helpCollapseActive,
      consoleLogs,
      clearConsoleLogs,
      // 新增功能
      collapsedPanels,
      togglePanel,
      toggleRightPanel,
      currentTheme,
      themes,
      changeTheme,
      toggleTheme,
      isFullscreen,
      toggleFullscreen,
      shortcutsDialogVisible,
      showShortcutsHelp,
      shortcutsData,
      splitSizes,
      playgroundContainer,
      handleResize
    };
  }
};
</script>

<style>
/* API示例对话框样式 */
.api-example-dialog {
  width: 80%;
  max-width: 900px;
}

.api-example-dialog .el-message-box__message {
  max-height: 70vh;
  overflow-y: auto;
}

.api-example-dialog code {
  background: #f0f2f5;
  padding: 2px 6px;
  border-radius: 3px;
  font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  font-size: 13px;
  color: #e83e8c;
}

.api-example-dialog pre {
  font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  font-size: 12px;
  line-height: 1.5;
  margin: 8px 0;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.api-example-dialog h4 {
  margin: 15px 0 10px 0;
  color: #303133;
}

.api-example-dialog strong {
  color: #409eff;
  display: block;
  margin-bottom: 5px;
}

/* ===== 全局暗色模式 Splitpanes 分隔线修复 ===== */
html.dark .splitpanes__splitter,
body.dark-theme .splitpanes__splitter,
.dark-theme .splitpanes__splitter,
.splitpanes.default-theme .splitpanes__splitter.dark-mode {
  background-color: rgba(255, 255, 255, 0.08) !important;
  background: rgba(255, 255, 255, 0.08) !important;
}

html.dark .splitpanes__splitter:hover,
body.dark-theme .splitpanes__splitter:hover,
.dark-theme .splitpanes__splitter:hover {
  background-color: var(--el-color-primary) !important;
  background: var(--el-color-primary) !important;
}
</style>

<style scoped>
/* ===== 加载动画和进度条 ===== */
.playground-loading-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0.98);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(5px);
}

.dark-theme .playground-loading-overlay {
  background: rgba(10, 10, 10, 0.98);
}

.playground-loading-card {
  width: 320px;
  padding: 30px 40px;
  background: #fff;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.12);
  border-radius: 12px;
  text-align: center;
  font-size: 14px;
}

.dark-theme .playground-loading-card {
  background: #1f1f1f;
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.5);
}

.loading-icon {
  margin-bottom: 20px;
  color: var(--el-color-primary);
}

.loading-text {
  font-size: 15px;
  font-weight: 500;
  color: var(--el-text-color-primary);
  margin-bottom: 16px;
}

.loading-bar {
  width: 100%;
  height: 6px;
  background: var(--el-fill-color-light);
  border-radius: 3px;
  margin: 12px 0;
  overflow: hidden;
}

.loading-bar-inner {
  height: 100%;
  background: linear-gradient(90deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
  transition: width 0.3s ease;
  border-radius: 3px;
}

.loading-percent {
  font-size: 13px;
  font-weight: 600;
  color: var(--el-color-primary);
  margin-bottom: 8px;
}

.loading-details {
  font-size: 12px;
  color: var(--el-text-color-secondary);
  min-height: 20px;
}

/* ===== 认证界面 ===== */
.playground-auth-loading {
  position: fixed;
  inset: 0;
  background: var(--el-bg-color);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--el-text-color-primary);
}

.playground-auth-overlay {
  position: fixed;
  inset: 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.playground-auth-card {
  width: 400px;
  padding: 40px;
  background: #fff;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
  border-radius: 16px;
  text-align: center;
}

.dark-theme .playground-auth-card {
  background: #1f1f1f;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5);
}

.auth-icon {
  margin-bottom: 24px;
  color: var(--el-color-primary);
}

.auth-title {
  font-size: 24px;
  font-weight: 600;
  color: var(--el-text-color-primary);
  margin-bottom: 8px;
}

.auth-subtitle {
  font-size: 14px;
  color: var(--el-text-color-secondary);
  margin-bottom: 24px;
}

.auth-input {
  margin-bottom: 16px;
}

.auth-error {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--el-color-danger);
  font-size: 13px;
  margin-bottom: 16px;
}

.auth-button {
  width: 100%;
  height: 44px;
  font-size: 16px;
  font-weight: 500;
}

/* ===== 容器布局 ===== */
.playground-container {
  padding: 10px 20px;
  min-height: calc(100vh - 20px);
  transition: all 0.3s ease;
}

/* 移动端：去掉边距，占满宽度 */
.playground-container.is-mobile {
  padding: 0;
  min-height: 100vh;
}

.playground-container.dark-theme {
  background-color: #0a0a0a;
}

.playground-container.fullscreen {
  padding: 0;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 9999;
  background: var(--el-bg-color);
}

.playground-container.fullscreen.dark-theme {
  background: #0a0a0a;
}

.playground-card {
  max-width: 100%;
  height: 100%;
  transition: all 0.3s ease;
}

/* 移动端：卡片占满宽度，去掉边距 */
.playground-container.is-mobile .playground-card {
  margin: 0;
  border-radius: 0;
  border-left: none;
  border-right: none;
}

.playground-container.is-mobile .playground-card :deep(.el-card__body) {
  padding: 12px;
}

.dark-theme .playground-card {
  background: #1a1a1a;
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .playground-card :deep(.el-card__header) {
  background: #1f1f1f;
  border-bottom-color: rgba(255, 255, 255, 0.1);
}

/* ===== 工具栏样式 ===== */
.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px 15px;
}

.header-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  flex: 1;
  min-width: 0;
  gap: 4px;
}

.header-left-top {
  display: flex;
  align-items: center;
  width: 100%;
}

.header-left-bottom {
  display: flex;
  align-items: center;
  width: 100%;
}

.title {
  font-size: 16px;
  font-weight: 600;
  color: var(--el-text-color-primary);
}

/* 面包屑导航样式 */
.breadcrumb-nav {
  display: flex;
  align-items: center;
  white-space: nowrap;
  flex-shrink: 0;
}

.breadcrumb-nav :deep(.el-breadcrumb) {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

.breadcrumb-nav :deep(.el-breadcrumb__inner) {
  font-size: 14px;
  color: var(--el-text-color-regular);
  white-space: nowrap;
  display: inline-block;
}

.breadcrumb-nav :deep(.el-breadcrumb__inner.is-link) {
  color: var(--el-text-color-primary);
  font-weight: 500;
}

.breadcrumb-nav :deep(.el-breadcrumb__separator) {
  margin: 0 8px;
  white-space: nowrap;
}

.breadcrumb-link {
  display: inline-flex;
  align-items: center;
  color: var(--el-text-color-primary);
  font-size: 14px;
  font-weight: 500;
  transition: color 0.2s;
}

.breadcrumb-link:hover {
  color: var(--el-color-primary);
}

.dark-theme .breadcrumb-link {
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .breadcrumb-link:hover {
  color: var(--el-color-primary);
}

.header-actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

/* 移动端：按钮左对齐 */
.playground-container.is-mobile .header-actions {
  justify-content: flex-start;
  width: 100%;
}

.playground-container.is-mobile .header-actions .el-button-group {
  margin-right: 0;
}

/* ===== Splitpanes样式 ===== */
.splitpanes {
  height: calc(100vh - 280px);
  min-height: 600px;
  background: transparent;
}

.splitpanes__pane {
  transition: all 0.3s ease;
  position: relative;
  background: transparent;
}

.splitpanes__splitter {
  background-color: var(--el-border-color-light);
  position: relative;
  transition: all 0.3s ease;
}

.splitpanes__splitter:hover {
  background-color: var(--el-color-primary);
  box-shadow: 0 0 8px rgba(64, 158, 255, 0.3);
}

.splitpanes--vertical > .splitpanes__splitter {
  width: 4px;
  margin: 0 -2px;
  cursor: col-resize;
}

/* 暗色模式下splitpanes分隔线 - 最强覆盖 */
.dark-theme .splitpanes__splitter,
.dark-theme.playground-container .splitpanes__splitter,
.playground-container.dark-theme .splitpanes__splitter,
body.dark-theme .splitpanes__splitter,
html.dark .splitpanes__splitter {
  background-color: rgba(255, 255, 255, 0.08) !important;
  background: rgba(255, 255, 255, 0.08) !important;
}

.dark-theme .splitpanes__splitter:hover,
.dark-theme.playground-container .splitpanes__splitter:hover,
.playground-container.dark-theme .splitpanes__splitter:hover,
body.dark-theme .splitpanes__splitter:hover,
html.dark .splitpanes__splitter:hover {
  background-color: var(--el-color-primary) !important;
  background: var(--el-color-primary) !important;
}

/* 暗色模式下splitpanes相关元素 */
.dark-theme .splitpanes,
.playground-container.dark-theme .splitpanes,
body.dark-theme .splitpanes,
html.dark .splitpanes {
  background: transparent !important;
}

.dark-theme .splitpanes__pane,
.playground-container.dark-theme .splitpanes__pane,
body.dark-theme .splitpanes__pane,
html.dark .splitpanes__pane {
  background: transparent !important;
}

.dark-theme .default-theme.splitpanes,
.playground-container.dark-theme .default-theme.splitpanes,
body.dark-theme .default-theme.splitpanes,
html.dark .default-theme.splitpanes {
  background: transparent !important;
}

/* ===== 卡片折叠样式 ===== */
.collapsible-card {
  transition: all 0.3s ease;
}

.card-header-with-collapse {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
}

.card-header-with-collapse span {
  font-weight: 500;
}

/* ===== 折叠过渡动画 ===== */
.collapse-enter-active,
.collapse-leave-active {
  transition: all 0.3s ease;
  max-height: 2000px;
  overflow: hidden;
}

.collapse-enter-from,
.collapse-leave-to {
  max-height: 0;
  opacity: 0;
  margin: 0;
  padding: 0;
}

/* 暗色模式下transition内的所有div */
.dark-theme .result-card .collapse-enter-active,
.dark-theme .result-card .collapse-leave-active,
.dark-theme .test-params-card .collapse-enter-active,
.dark-theme .test-params-card .collapse-leave-active {
  background-color: transparent !important;
}

.dark-theme .result-card .collapse-enter-active > div,
.dark-theme .result-card .collapse-leave-active > div,
.dark-theme .test-params-card .collapse-enter-active > div,
.dark-theme .test-params-card .collapse-leave-active > div {
  background-color: transparent !important;
}

/* 暗色模式下明确处理transition包裹的内容 */
.dark-theme .result-card > div > div,
.dark-theme .result-card .el-card__body > div > div {
  background-color: transparent !important;
}

/* 暗色模式下强制所有嵌套div背景透明 */
.dark-theme .result-card div[v-show],
.dark-theme .result-card .result-content,
.dark-theme .test-params-card div[v-show] {
  background-color: transparent !important;
}

/* 暗色模式下el-card内所有div背景 */
.dark-theme .el-card__body div {
  background-color: transparent;
}

/* 暗色模式下特殊元素保持深色背景 */
.dark-theme .result-debug-box,
.dark-theme .console-container,
.dark-theme pre,
.dark-theme .stack-trace pre {
  background-color: #1a1a1a !important;
}

/* 暗色模式下Alert组件不要透明 */
.dark-theme .el-alert {
  background-color: rgba(255, 255, 255, 0.05) !important;
}

/* 暗色模式下vue transition元素 */
.dark-theme .collapse-enter-from,
.dark-theme .collapse-leave-to {
  background-color: transparent !important;
}

/* 暗色模式下所有可能的白色背景元素 - 最强覆盖 */
.dark-theme .playground-card div,
.dark-theme .playground-card .el-card div {
  background: transparent;
}

/* 暗色模式下必须保持背景的元素 */
.dark-theme .playground-card,
.dark-theme .test-params-card,
.dark-theme .result-card,
.dark-theme .help-card,
.dark-theme .console-card {
  background: #1f1f1f !important;
}

.dark-theme .el-card__header {
  background: #252525 !important;
}

.dark-theme .el-card__body {
  background: #1f1f1f !important;
}

/* 暗色模式下v-show控制的div */
.dark-theme [v-show] {
  background: transparent !important;
}

/* 暗色模式下transition组件的div */
.dark-theme .el-collapse-transition,
.dark-theme [style*="max-height"] {
  background: transparent !important;
}

/* 暗色模式下确保没有白色背景的通用规则 */
.dark-theme * {
  scrollbar-color: #3c3c3c #1a1a1a;
}

/* 暗色模式下强制覆盖可能的白色背景 */
.dark-theme .test-section > div,
.dark-theme .test-section > div > div {
  background-color: transparent !important;
}

/* 暗色模式下分隔线和面板的全局样式 */
.dark-theme .splitpanes.default-theme .splitpanes__splitter {
  background-color: rgba(255, 255, 255, 0.08) !important;
}

.dark-theme .splitpanes.default-theme .splitpanes__splitter::before,
.dark-theme .splitpanes.default-theme .splitpanes__splitter::after {
  background-color: rgba(255, 255, 255, 0.08) !important;
}

.dark-theme .editor-pane,
.dark-theme .test-pane {
  background: transparent !important;
}

/* 确保编辑器面板和测试面板高度一致 */
.editor-pane,
.test-pane {
  height: 100%;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* 暗色模式下确保所有分隔线都是深色 - 终极覆盖 */
.dark-theme .splitpanes__splitter,
.dark-theme .splitpanes.default-theme > .splitpanes__splitter,
.dark-theme .splitpanes--vertical > .splitpanes__splitter,
.playground-container.dark-theme .splitpanes__splitter,
.playground-container.dark-theme .splitpanes.default-theme > .splitpanes__splitter,
.playground-container.dark-theme .splitpanes--vertical > .splitpanes__splitter,
body.dark-theme .playground-container .splitpanes__splitter,
html.dark .playground-container .splitpanes__splitter,
.splitpanes.default-theme .dark-theme .splitpanes__splitter,
div.dark-theme .splitpanes__splitter {
  background-color: rgba(255, 255, 255, 0.08) !important;
  background: rgba(255, 255, 255, 0.08) !important;
  border: none !important;
  border-color: rgba(255, 255, 255, 0.08) !important;
}

/* 暗色模式下分隔线hover效果 */
.dark-theme .splitpanes__splitter:hover,
.dark-theme .splitpanes.default-theme > .splitpanes__splitter:hover,
.playground-container.dark-theme .splitpanes__splitter:hover,
body.dark-theme .playground-container .splitpanes__splitter:hover,
html.dark .playground-container .splitpanes__splitter:hover {
  background-color: var(--el-color-primary) !important;
  background: var(--el-color-primary) !important;
}

/* ===== 优化的右侧面板折叠按钮 ===== */
.panel-collapse-btn {
  position: absolute;
  top: 50%;
  left: -20px;
  transform: translateY(-50%);
  width: 20px;
  height: 80px;
  background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
  border-radius: 10px 0 0 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 10;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  color: white;
  box-shadow: -2px 0 8px rgba(0, 0, 0, 0.1);
}

.panel-collapse-btn:hover {
  left: -22px;
  width: 24px;
  box-shadow: -4px 0 12px rgba(0, 0, 0, 0.15);
  background: linear-gradient(135deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
}

.panel-collapse-btn:active {
  transform: translateY(-50%) scale(0.95);
}

.panel-collapse-btn .el-icon {
  font-size: 14px;
  transition: transform 0.3s ease;
}

.panel-collapse-btn:hover .el-icon {
  transform: scale(1.2);
}

.panel-expand-btn {
  position: fixed;
  right: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 32px;
  height: 120px;
  background: linear-gradient(180deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
  border-radius: 8px 0 0 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  z-index: 100;
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  color: white;
  gap: 8px;
  box-shadow: -3px 0 10px rgba(0, 0, 0, 0.15);
  padding: 15px 0;
}

.panel-expand-btn:hover {
  width: 36px;
  right: -2px;
  box-shadow: -6px 0 16px rgba(0, 0, 0, 0.2);
  background: linear-gradient(180deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
}

.panel-expand-btn:active {
  transform: translateY(-50%) scale(0.98);
}

.panel-expand-btn .el-icon {
  font-size: 18px;
  transition: transform 0.3s ease;
}

.panel-expand-btn:hover .el-icon {
  transform: scale(1.15);
}

/* ===== 控制台展开按钮 ===== */
.console-expand-btn {
  position: fixed;
  bottom: 20px;
  right: 20px;
  background: linear-gradient(135deg, var(--el-color-primary) 0%, var(--el-color-primary-light-3) 100%);
  color: white;
  padding: 10px 20px;
  border-radius: 20px;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
  z-index: 100;
  font-size: 14px;
  font-weight: 500;
}

.console-expand-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
  background: linear-gradient(135deg, var(--el-color-primary-light-3) 0%, var(--el-color-primary) 100%);
}

.console-expand-btn:active {
  transform: translateY(0);
}

/* ===== 按钮动画 ===== */
.fade-enter-active,
.fade-leave-active {
  transition: all 0.3s ease;
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
  transform: scale(0.9);
}

.slide-up-enter-active,
.slide-up-leave-active {
  transition: all 0.3s ease;
}

.slide-up-enter-from {
  opacity: 0;
  transform: translateY(20px);
}

.slide-up-leave-to {
  opacity: 0;
  transform: translateY(-20px);
}

/* ===== 文件标签页 ===== */
.file-tabs-container {
  margin-bottom: 12px;
}

.file-tabs-wrapper {
  display: flex;
  align-items: center;
  gap: 8px;
}

.file-tabs {
  flex: 1;
}

.file-tabs :deep(.el-tabs__header) {
  margin: 0;
}

.file-tabs :deep(.el-tabs__item) {
  padding: 0 15px;
  height: 32px;
  line-height: 32px;
  font-size: 13px;
}

.file-tabs :deep(.el-tabs__item.is-active) {
  background-color: var(--el-color-primary-light-9);
  color: var(--el-color-primary);
}

.dark-theme .file-tabs :deep(.el-tabs__item.is-active) {
  background-color: rgba(64, 158, 255, 0.2);
  color: var(--el-color-primary);
}

.new-file-tab-btn {
  flex-shrink: 0;
}

/* ===== 编辑器区域 ===== */
.editor-section {
  border-radius: 4px;
  overflow: hidden;
  border: 1px solid var(--el-border-color);
  background: var(--el-bg-color);
  height: 100%;
  display: flex;
  flex-direction: column;
}

/* ===== 测试区域 ===== */
.test-section {
  height: 100%;
  overflow-y: auto;
  padding-right: 5px;
  position: relative;
}

.test-section::-webkit-scrollbar {
  width: 6px;
}

.test-section::-webkit-scrollbar-thumb {
  background: var(--el-border-color-darker);
  border-radius: 3px;
}

.test-section::-webkit-scrollbar-thumb:hover {
  background: var(--el-border-color);
}

.test-params-card,
.result-card,
.help-card {
  margin-bottom: 10px;
  transition: all 0.3s ease;
}

.test-params-card :deep(.el-card__body) {
  padding: 12px;
}

.dark-theme .test-params-card,
.dark-theme .result-card,
.dark-theme .help-card {
  background: #1f1f1f;
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .test-params-card :deep(.el-card__header),
.dark-theme .result-card :deep(.el-card__header),
.dark-theme .help-card :deep(.el-card__header) {
  background: #252525;
  border-bottom-color: rgba(255, 255, 255, 0.1);
}

/* 测试参数表单布局 */
.test-params-form {
  padding: 0;
}

.test-params-form :deep(.el-form-item__content) {
  margin-left: 0 !important;
}

.test-params-form .share-url-item {
  margin-bottom: 10px;
}

.test-params-form .password-item {
  margin-bottom: 10px;
}

.test-params-form .method-item-horizontal {
  margin-bottom: 10px;
}

.test-params-form .method-item-horizontal :deep(.el-radio-group) {
  display: flex;
  flex-direction: row;
  gap: 6px;
  flex-wrap: nowrap;
  width: 100%;
}

.test-params-form .method-item-horizontal :deep(.el-radio) {
  margin-right: 0;
  white-space: nowrap;
  flex: 0 0 auto;
}

.test-params-form .method-item-horizontal :deep(.el-radio__label) {
  padding-left: 6px;
  font-size: 13px;
}

.test-params-form .button-item {
  margin-bottom: 0;
}

/* 暗色模式下的表单样式修复 */
.dark-theme .test-params-card :deep(.el-form-item__label),
.dark-theme .result-card :deep(.el-form-item__label) {
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .test-params-card :deep(.el-input__wrapper) {
  background-color: #1a1a1a;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.15) inset;
}

.dark-theme .test-params-card :deep(.el-input__wrapper:hover) {
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.25) inset;
}

.dark-theme .test-params-card :deep(.el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 1px var(--el-color-primary) inset;
}

.dark-theme .test-params-card :deep(.el-input__inner) {
  color: rgba(255, 255, 255, 0.85);
  background-color: transparent;
}

.dark-theme .test-params-card :deep(.el-radio__label) {
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .test-params-card :deep(.el-radio__inner) {
  background-color: #1a1a1a;
  border-color: rgba(255, 255, 255, 0.3);
}

.dark-theme .test-params-card :deep(.el-radio__input.is-checked .el-radio__inner) {
  background-color: var(--el-color-primary);
  border-color: var(--el-color-primary);
}

.dark-theme .test-params-card :deep(.el-radio:hover .el-radio__inner) {
  border-color: var(--el-color-primary);
}

.editor-section {
  margin-bottom: 20px;
}

.test-section {
  display: flex;
  flex-direction: column;
}

.test-params-card,
.result-card {
  width: 100%;
}

.result-content {
  max-height: 500px;
  overflow-y: auto;
}

.dark-theme .result-content {
  background-color: transparent;
  color: rgba(255, 255, 255, 0.85);
}

.result-section {
  margin-bottom: 15px;
  background-color: transparent;
}

.dark-theme .result-section {
  background-color: transparent !important;
}

.section-title {
  font-weight: bold;
  margin-bottom: 8px;
  color: #606266;
}

.result-debug-box {
  margin-bottom: 10px;
  padding: 10px;
  background: #f5f5f5;
  border-radius: 4px;
  word-break: break-all;
}

.dark-theme .result-debug-box {
  background: #1a1a1a;
  color: rgba(255, 255, 255, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.dark-theme .result-debug-box strong {
  color: rgba(255, 255, 255, 0.9);
}

.logs-container {
  max-height: 200px;
  overflow-y: auto;
  border: 1px solid #dcdfe6;
  border-radius: 4px;
  padding: 10px;
  background-color: #f5f7fa;
}

.log-entry {
  display: flex;
  align-items: center;
  padding: 4px 0;
  font-size: 12px;
  font-family: 'Courier New', monospace;
}

.log-time {
  color: #909399;
  margin-right: 8px;
  min-width: 80px;
}

.log-level {
  font-weight: bold;
  margin-right: 8px;
  min-width: 50px;
}

.log-debug .log-level {
  color: #909399;
}

.log-info .log-level {
  color: #409eff;
}

.log-warn .log-level {
  color: #e6a23c;
}

.log-error .log-level {
  color: #f56c6c;
}

.log-message {
  flex: 1;
  word-break: break-all;
}

.stack-trace {
  margin-top: 10px;
}

.stack-trace pre {
  background-color: #f5f7fa;
  padding: 10px;
  border-radius: 4px;
  font-size: 12px;
  overflow-x: auto;
}

.dark-theme .stack-trace :deep(.el-collapse) {
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .stack-trace :deep(.el-collapse-item__header) {
  background-color: #1a1a1a;
  color: rgba(255, 255, 255, 0.85);
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .stack-trace :deep(.el-collapse-item__wrap) {
  background-color: #1a1a1a;
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .stack-trace :deep(.el-collapse-item__content) {
  color: rgba(255, 255, 255, 0.85);
}

/* ===== 新建文件对话框样式 ===== */
.new-file-dialog .form-tip {
  font-size: 12px;
  color: var(--el-text-color-secondary);
  margin-top: 4px;
  line-height: 1.4;
}

.empty-result {
  text-align: center;
  padding: 40px 0;
  background-color: transparent;
}

.dark-theme .empty-result {
  background-color: transparent;
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .logs-container {
  background-color: #1e1e1e;
  border-color: #3c3c3c;
  color: #d4d4d4;
}

.dark-theme .stack-trace pre {
  background-color: #1e1e1e;
  color: #d4d4d4;
}

.dark-theme .section-title {
  color: rgba(255, 255, 255, 0.9);
}

.console-card {
  margin-top: 12px;
}

.console-container {
  max-height: 400px;
  overflow-y: auto;
  border: 1px solid var(--el-border-color-light);
  border-radius: 6px;
  padding: 12px;
  background-color: #fafafa;
  font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  font-size: 13px;
  transition: all 0.3s ease;
}

.dark-theme .console-container {
  background-color: #1a1a1a;
  border-color: rgba(255, 255, 255, 0.15);
  color: rgba(255, 255, 255, 0.85);
}

.console-entry {
  display: flex;
  align-items: flex-start;
  padding: 8px 10px;
  margin: 4px 0;
  line-height: 1.6;
  word-break: break-all;
  border-radius: 4px;
  border-left: 3px solid transparent;
  transition: all 0.2s ease;
}

.console-entry:hover {
  background: rgba(0, 0, 0, 0.03);
}

.dark-theme .console-entry:hover {
  background: rgba(255, 255, 255, 0.05);
}

.console-time {
  color: var(--el-text-color-secondary);
  margin-right: 10px;
  min-width: 80px;
  flex-shrink: 0;
  font-size: 11px;
  opacity: 0.8;
}

.console-level {
  font-weight: 600;
  margin-right: 10px;
  min-width: 50px;
  flex-shrink: 0;
  font-size: 12px;
}

.console-debug {
  border-left-color: var(--el-text-color-secondary);
  background: var(--el-fill-color-lighter);
}

.console-debug .console-level {
  color: var(--el-text-color-secondary);
}

.console-info {
  border-left-color: var(--el-color-info);
  background: var(--el-color-info-light-9);
}

.console-info .console-level {
  color: var(--el-color-info);
}

.console-warn {
  border-left-color: var(--el-color-warning);
  background: var(--el-color-warning-light-9);
}

.console-warn .console-level {
  color: var(--el-color-warning);
}

.console-error {
  border-left-color: var(--el-color-danger);
  background: var(--el-color-danger-light-9);
}

.console-error .console-level {
  color: var(--el-color-danger);
}

/* JavaScript 日志样式（绿色主题） */
.console-js-source {
  border-left-color: var(--el-color-success) !important;
  background: var(--el-color-success-light-9) !important;
}

.dark-theme .console-js-source {
  background: rgba(103, 194, 58, 0.15) !important;
}

.console-source-tag {
  display: inline-block;
  background: linear-gradient(135deg, var(--el-color-success) 0%, var(--el-color-success-light-3) 100%);
  color: white;
  font-size: 10px;
  padding: 3px 8px;
  border-radius: 10px;
  margin-right: 8px;
  font-weight: 600;
  flex-shrink: 0;
  box-shadow: 0 2px 4px rgba(103, 194, 58, 0.3);
}

.console-message {
  flex: 1;
  color: var(--el-text-color-primary);
  font-size: 13px;
}

.empty-console {
  text-align: center;
  color: var(--el-text-color-placeholder);
  padding: 40px 0;
  font-size: 14px;
}

.help-content {
  text-align: left;
  color: var(--el-text-color-regular);
  line-height: 1.8;
}

.help-content h3 {
  margin-top: 20px;
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: 600;
  color: var(--el-color-primary);
}

.help-content h4 {
  margin-top: 15px;
  margin-bottom: 10px;
  font-size: 14px;
  font-weight: 500;
  color: var(--el-text-color-primary);
}

.help-content ul,
.help-content ol {
  margin: 10px 0;
  padding-left: 24px;
}

.help-content li {
  margin: 8px 0;
  line-height: 1.7;
}

.help-content code {
  background: var(--el-fill-color);
  padding: 3px 8px;
  border-radius: 4px;
  font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  font-size: 0.9em;
  color: var(--el-color-danger);
  border: 1px solid var(--el-border-color-lighter);
}

.help-content pre {
  background: var(--el-fill-color-light);
  padding: 12px;
  border-radius: 6px;
  overflow-x: auto;
  font-size: 13px;
  border: 1px solid var(--el-border-color);
  line-height: 1.6;
  margin: 10px 0;
}

.help-content a {
  color: var(--el-color-primary);
  text-decoration: none;
  transition: all 0.3s;
  font-weight: 500;
}

.help-content a:hover {
  color: var(--el-color-primary-light-3);
  text-decoration: underline;
}

.help-content p {
  margin: 10px 0;
  line-height: 1.7;
}

.parser-list-section {
  margin-top: 20px;
}

/* ===== 响应式布局 ===== */
/* 移动端布局：内容自然向下流动 */
.mobile-layout {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.mobile-layout .editor-section {
  width: 100%;
  margin: 0;
  margin-bottom: 12px;
  padding: 0;
}

/* 移动端编辑器容器：去掉所有边距 */
.playground-container.is-mobile .mobile-layout .editor-section {
  margin: 0;
  padding: 0;
  position: relative;
}

.playground-container.is-mobile .mobile-layout .editor-section :deep(.monaco-editor-container) {
  border-radius: 0;
  border-left: none;
  border-right: none;
}

/* 移动端编辑器悬浮操作按钮 */
.mobile-editor-actions {
  position: absolute;
  bottom: 20px;
  right: 20px;
  z-index: 10;
  display: flex;
  gap: 8px;
}

.mobile-editor-actions .editor-action-btn {
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
  background: var(--el-bg-color);
  border: 1px solid var(--el-border-color);
}

.mobile-editor-actions .editor-action-btn:hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
  transform: translateY(-2px);
  transition: all 0.2s ease;
}

.dark-theme .mobile-editor-actions .editor-action-btn {
  background: rgba(30, 30, 30, 0.95);
  border-color: rgba(255, 255, 255, 0.1);
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .mobile-editor-actions .editor-action-btn:hover {
  background: rgba(40, 40, 40, 0.95);
  border-color: rgba(255, 255, 255, 0.2);
}

.mobile-test-section {
  width: 100%;
  height: auto !important;
  overflow-y: visible !important;
  padding: 0;
}

.mobile-test-section .test-params-card,
.mobile-test-section .result-card {
  margin-bottom: 12px;
}

.playground-container.is-mobile .playground-loading-card {
  width: 90%;
  max-width: 320px;
  padding: 24px 30px;
}

.playground-container.is-mobile .playground-auth-card {
  width: 90%;
  max-width: 400px;
  padding: 30px 24px;
}

@media screen and (max-width: 1200px) {
  .splitpanes {
    min-height: 400px;
  }
  
  .header-actions {
    flex-wrap: wrap;
  }
  
  .console-container {
    max-height: 250px;
  }
  
  .empty-console {
    padding: 20px 0;
  }
}

@media screen and (max-width: 768px) {
  .playground-container {
    padding: 10px;
  }
  
  .card-header {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
  }
  
  .console-container {
    max-height: 300px;
    padding: 8px;
  }
  
  .empty-console {
    padding: 12px 0;
    font-size: 13px;
  }
  
  .console-entry {
    font-size: 12px;
    padding: 6px 0;
  }
  
  .header-actions {
    width: 100%;
    justify-content: flex-start;
  }
  
  .panel-expand-btn {
    right: 10px;
  }
  
  .test-params-form .method-item-horizontal :deep(.el-radio-group) {
    flex-direction: column;
    gap: 8px;
  }
  
  /* 移动端结果区域自适应高度 */
  .result-content {
    max-height: none !important;
    overflow-y: visible !important;
  }
  
  /* 移动端测试区域不使用固定高度 */
  .test-section {
    height: auto !important;
    overflow-y: visible !important;
  }
  
  /* 移动端对话框样式 */
  .publish-dialog :deep(.el-dialog) {
    margin: 5vh auto !important;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
  }
  
  .publish-dialog :deep(.el-dialog__body) {
    flex: 1;
    overflow-y: auto;
    padding: 15px;
  }
  
  .publish-code-textarea :deep(.el-textarea__inner) {
    font-size: 12px;
    font-family: 'Monaco', 'Menlo', 'Courier New', monospace;
  }
  
  .publish-checklist {
    font-size: 13px;
  }
  
  .publish-checklist ul {
    line-height: 1.8;
  }
  
  .publish-checklist li {
    margin-bottom: 4px;
  }
  
  .dialog-footer-mobile {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    flex-wrap: wrap;
  }
  
  .shortcuts-dialog :deep(.el-dialog) {
    margin: 5vh auto !important;
    max-height: 90vh;
  }
  
  .shortcuts-dialog :deep(.el-dialog__body) {
    padding: 15px;
    max-height: calc(90vh - 120px);
    overflow-y: auto;
  }
  
  .shortcuts-table :deep(.el-table__body) {
    font-size: 13px;
  }
}

/* ===== 改进的滚动条样式 ===== */
.test-section::-webkit-scrollbar,
.console-container::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.test-section::-webkit-scrollbar-track,
.console-container::-webkit-scrollbar-track {
  background: var(--el-fill-color-lighter);
  border-radius: 4px;
}

.test-section::-webkit-scrollbar-thumb,
.console-container::-webkit-scrollbar-thumb {
  background: var(--el-border-color-darker);
  border-radius: 4px;
  transition: background 0.3s ease;
}

.test-section::-webkit-scrollbar-thumb:hover,
.console-container::-webkit-scrollbar-thumb:hover {
  background: var(--el-border-color-extra-light);
}

/* ===== 暗色主题优化 ===== */
.dark-theme .editor-section {
  border-color: rgba(255, 255, 255, 0.15);
  background: #1a1a1a;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

/* 暗色模式下所有el-card的body部分背景 */
.dark-theme .test-params-card :deep(.el-card__body),
.dark-theme .result-card :deep(.el-card__body),
.dark-theme .help-card :deep(.el-card__body),
.dark-theme .console-card :deep(.el-card__body) {
  background: #1f1f1f !important;
  color: rgba(255, 255, 255, 0.85);
}

/* 暗色模式下所有可能的白色背景容器 */
.dark-theme .result-card :deep(div) {
  background-color: transparent;
}

.dark-theme .result-card :deep(pre) {
  background-color: #1a1a1a;
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .result-card :deep(code) {
  background-color: #252525;
  color: rgba(255, 255, 255, 0.85);
}

/* 强制覆盖所有可能有白色背景的元素 */
.dark-theme .result-card > div,
.dark-theme .result-card .el-card__body > div {
  background-color: transparent !important;
}

/* 暗色模式下的按钮样式修复 */
.dark-theme .test-params-card :deep(.el-button--primary) {
  background-color: var(--el-color-primary);
  border-color: var(--el-color-primary);
}

.dark-theme .test-params-card :deep(.el-button--primary:hover) {
  background-color: var(--el-color-primary-light-3);
  border-color: var(--el-color-primary-light-3);
}

/* 暗色模式下的Alert组件 */
.dark-theme .result-card :deep(.el-alert) {
  background-color: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

.dark-theme .result-card :deep(.el-alert.el-alert--success) {
  background-color: rgba(103, 194, 58, 0.15);
  border-color: rgba(103, 194, 58, 0.3);
}

.dark-theme .result-card :deep(.el-alert.el-alert--error) {
  background-color: rgba(245, 108, 108, 0.15);
  border-color: rgba(245, 108, 108, 0.3);
}

.dark-theme .result-card :deep(.el-alert__title) {
  color: rgba(255, 255, 255, 0.9);
}

/* 暗色模式下的Empty组件 */
.dark-theme .result-card :deep(.el-empty__description) {
  color: rgba(255, 255, 255, 0.5);
}

/* 暗色模式下的JsonViewer */
.dark-theme .result-card :deep(.jv-container) {
  background-color: #1a1a1a !important;
}

.dark-theme .result-card :deep(.jv-code) {
  background-color: #1a1a1a !important;
  color: rgba(255, 255, 255, 0.85) !important;
}

.dark-theme .result-card :deep(.jv-container .jv-code) {
  background-color: #1a1a1a !important;
}

.dark-theme .result-card :deep(.json-viewer) {
  background-color: #1a1a1a !important;
}

.dark-theme .result-card :deep(.jv-node) {
  color: rgba(255, 255, 255, 0.85) !important;
}

/* 暗色模式下的调试区域 */
.dark-theme .result-section > div[style*="background"] {
  background: #1a1a1a !important;
  color: rgba(255, 255, 255, 0.85) !important;
}

/* 暗色模式下的执行时间和其他文本 */
.dark-theme .result-section > div {
  color: rgba(255, 255, 255, 0.85);
}

/* 暗色模式下的卡片折叠按钮 */
.dark-theme .card-header-with-collapse .el-button {
  color: rgba(255, 255, 255, 0.85);
}

.dark-theme .card-header-with-collapse .el-button:hover {
  color: var(--el-color-primary);
}

.dark-theme .console-card {
  background: #1f1f1f;
  border-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .console-card :deep(.el-card__header) {
  background: #252525;
  border-bottom-color: rgba(255, 255, 255, 0.1);
}

.dark-theme .console-container {
  background: #1a1a1a;
  border-color: rgba(255, 255, 255, 0.15);
}

.dark-theme .console-entry {
  border-left-color: rgba(255, 255, 255, 0.2);
}

.dark-theme .console-entry:hover {
  background: rgba(255, 255, 255, 0.08);
}

.dark-theme .section-title {
  color: rgba(255, 255, 255, 0.9);
}

.dark-theme .console-info {
  background: rgba(64, 158, 255, 0.1);
}

.dark-theme .console-warn {
  background: rgba(230, 162, 60, 0.1);
}

.dark-theme .console-error {
  background: rgba(245, 108, 108, 0.1);
}

.dark-theme .console-debug {
  background: rgba(144, 147, 153, 0.1);
}

/* ===== 动画效果优化 ===== */
.collapsible-card {
  transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}

.el-button {
  transition: all 0.2s ease;
}

.el-button:active {
  transform: scale(0.95);
}

/* ===== 帮助卡片样式 ===== */
.help-card {
  background: var(--el-fill-color-lighter);
}

.help-card :deep(.el-card__body) {
  max-height: 600px;
  overflow-y: auto;
}

/* ===== 表格样式优化 ===== */
.parser-list-section :deep(.el-table) {
  font-size: 14px;
}

.parser-list-section :deep(.el-table__row) {
  transition: background-color 0.2s ease;
}

.parser-list-section :deep(.el-table__row:hover) {
  background-color: var(--el-fill-color-light);
}

/* ===== 暗色模式下 Splitpanes 分隔线最终覆盖 ===== */
.dark-theme :deep(.splitpanes__splitter),
.playground-container.dark-theme :deep(.splitpanes__splitter) {
  background-color: rgba(255, 255, 255, 0.08) !important;
  background: rgba(255, 255, 255, 0.08) !important;
}

.dark-theme :deep(.splitpanes__splitter:hover),
.playground-container.dark-theme :deep(.splitpanes__splitter:hover) {
  background-color: var(--el-color-primary) !important;
  background: var(--el-color-primary) !important;
}

/* 使用属性选择器覆盖可能的内联样式 */
.dark-theme [class*="splitpanes__splitter"],
.playground-container.dark-theme [class*="splitpanes__splitter"] {
  background-color: rgba(255, 255, 255, 0.08) !important;
  background: rgba(255, 255, 255, 0.08) !important;
}
</style>

