<template>
  <el-container
    :class="{ 'mobile-mode': isMobile }"
    v-loading="loading"
    element-loading-text="正在加载接口列表..."
    element-loading-background="rgba(255, 255, 255, 1)"
  >
    <el-header v-if="isMobile" class="mobile-header">
      <el-button :icon="Menu" circle text class="menu-toggle-btn" @click="toggleMenu" />
      <h2>API 文档中心</h2>
      <span class="mobile-header-spacer" />
    </el-header>

    <el-aside
      :width="isMobile ? '100%' : '280px'"
      class="sidebar"
      v-show="(!isMobile || (isMobile && showMenu)) && !loadError"
    >
      <div class="sidebar-inner">
        <div class="sidebar-header">
          <div class="sidebar-brand">
            <el-icon class="brand-icon"><Document /></el-icon>
            <div class="brand-text">
              <span class="brand-title">API 文档中心</span>
              <span v-if="!loading && !loadError" class="brand-subtitle">
                共 {{ apis.length }} 个接口
              </span>
            </div>
          </div>
          <el-button
            v-if="isMobile"
            :icon="Close"
            circle
            text
            class="sidebar-close-btn"
            @click="toggleMenu"
          />
        </div>

        <div class="sidebar-search">
          <el-input
            placeholder="搜索接口..."
            v-model="searchQuery"
            clearable
            :prefix-icon="Search"
            :disabled="loading || !!loadError"
          />
        </div>

        <div class="sidebar-content">
          <div v-if="loadError" class="sidebar-error">
            <el-empty description="加载失败" :image-size="80">
              <el-button type="primary" size="small" @click="location.reload()">
                重新加载
              </el-button>
            </el-empty>
          </div>

          <template v-else>
            <div v-if="currentPath.length > 0" class="breadcrumb-nav">
              <div class="breadcrumb-toolbar">
                <el-button link :icon="ArrowLeft" @click="goBack" class="breadcrumb-btn">
                  返回
                </el-button>
                <el-button link :icon="HomeFilled" @click="goHome" class="breadcrumb-btn">
                  根目录
                </el-button>
              </div>
              <div class="breadcrumb-path">
                <span class="breadcrumb-tag breadcrumb-clickable" @click="goHome">根目录</span>
                <template v-for="(path, index) in currentPath" :key="index">
                  <el-icon class="breadcrumb-chevron"><ArrowRight /></el-icon>
                  <span
                    class="breadcrumb-tag"
                    :class="{
                      'breadcrumb-clickable': index < currentPath.length - 1,
                      'breadcrumb-current': index === currentPath.length - 1,
                    }"
                    @click="index < currentPath.length - 1 && navigateToPath(index)"
                  >
                    {{ path }}
                  </span>
                </template>
              </div>
            </div>

            <el-empty
              v-if="
                !loading &&
                !loadError &&
                currentLevelNodes.length === 0 &&
                currentLevelApis.length === 0
              "
              description="没有找到相关接口"
              :image-size="64"
              class="sidebar-empty"
            />

            <el-menu
              v-else
              class="menu-vertical"
              :default-active="activeMenuIndex"
            >
              <template v-for="node in currentLevelNodes" :key="node.key">
                <el-menu-item
                  v-if="
                    !node.isUngrouped && (node.children.length > 0 || node.apis.length > 0)
                  "
                  :index="node.key"
                  @click="enterGroup(node)"
                  class="menu-folder-item"
                  :disabled="loading"
                >
                  <div class="menu-item-inner">
                    <el-icon class="menu-item-icon folder"><Folder /></el-icon>
                    <span class="menu-item-label">{{ node.displayName }}</span>
                    <span class="menu-item-count">{{ getNodeApiCount(node) }}</span>
                    <el-icon class="menu-item-arrow"><ArrowRight /></el-icon>
                  </div>
                </el-menu-item>

                <el-menu-item
                  v-else-if="node.isUngrouped"
                  :index="node.key"
                  @click="
                    goToApi(node.apis[0]);
                    isMobile && toggleMenu();
                  "
                  class="menu-api-item"
                  :disabled="loading"
                >
                  <div class="menu-item-inner">
                    <el-icon class="menu-item-icon api"><Document /></el-icon>
                    <span class="menu-item-label">{{ node.displayName }}</span>
                  </div>
                </el-menu-item>
              </template>

              <template v-if="currentLevelApis.length > 0">
                <el-menu-item
                  v-if="currentLevelNodes.length > 0"
                  index="__section_apis__"
                  disabled
                  class="menu-section-item"
                >
                  <span class="menu-section-label">接口</span>
                </el-menu-item>
                <el-menu-item
                  v-for="api in currentLevelApis"
                  :key="api.uniqueId"
                  :index="api.uniqueId"
                  @click="
                    goToApi(api);
                    isMobile && toggleMenu();
                  "
                  class="menu-api-item"
                  :disabled="loading"
                >
                  <div class="menu-item-inner">
                    <el-icon class="menu-item-icon api"><Document /></el-icon>
                    <span class="menu-item-label">{{
                      getCurrentNodeApiDisplayName(api)
                    }}</span>
                  </div>
                </el-menu-item>
              </template>
            </el-menu>
          </template>
        </div>
      </div>
    </el-aside>

    <el-main class="main-content">
      <!-- 接口列表加载失败时全屏显示错误 -->
      <div v-if="loadError" class="error-container fullscreen-error">
        <el-result icon="error" title="加载失败" :sub-title="loadError">
          <template #extra>
            <el-button type="primary" @click="location.reload()">重新加载</el-button>
          </template>
        </el-result>
      </div>

      <template v-else>
        <div class="content-frame">
          <div class="content-nav-wrap">
            <div class="content-section content-nav-bar">
              <div class="content-nav-tabs">
                <button
                  type="button"
                  class="content-nav-tab"
                  :class="{ active: activeTab === 'docs' }"
                  @click="activeTab = 'docs'"
                >
                  接口文档
                </button>
                <button
                  type="button"
                  class="content-nav-tab"
                  :class="{ active: activeTab === 'common' }"
                  @click="activeTab = 'common'"
                >
                  通用信息
                </button>
              </div>
              <el-button
                type="primary"
                plain
                size="small"
                :icon="Download"
                @click="showExportDrawer = true"
              >
                导出文档
              </el-button>
            </div>
          </div>

          <div class="content-frame-body">
            <div v-show="activeTab === 'docs'" class="content-tab-panel">
          <!-- README引导页 -->
          <div v-if="!currentApi" class="content-page readme-guide">
            <div class="content-section page-header-card page-header-card-center">
              <div class="page-header-main">
                <el-icon class="page-hero-icon"><Document /></el-icon>
                <div>
                  <h1 class="page-hero-title">接口文档中心</h1>
                  <p class="page-hero-desc">
                    欢迎使用 API 文档中心，这里提供了完整的接口文档和使用说明
                  </p>
                </div>
              </div>
            </div>

            <div class="readme-grid">
              <div class="readme-card">
                <div class="readme-card-num">01</div>
                <h3>浏览接口</h3>
                <p>在左侧菜单中浏览所有可用的接口，接口按模块分组显示。</p>
                <ul>
                  <li>点击文件夹进入下一级目录</li>
                  <li>点击接口名称查看详细文档</li>
                  <li>使用搜索框快速查找接口</li>
                </ul>
              </div>

              <div class="readme-card">
                <div class="readme-card-num">02</div>
                <h3>查看接口详情</h3>
                <p>点击任意接口后，右侧会显示该接口的详细信息，包括：</p>
                <ul>
                  <li>请求参数说明</li>
                  <li>响应数据结构</li>
                  <li>调用示例（cURL、JavaScript）</li>
                </ul>
              </div>

              <div class="readme-card">
                <div class="readme-card-num">03</div>
                <h3>导出文档</h3>
                <p>点击上方「导出文档」按钮，可以：</p>
                <ul>
                  <li>一键导出所有接口文档</li>
                  <li>按需选择接口进行导出</li>
                  <li>导出为 Markdown 格式</li>
                </ul>
              </div>

              <div class="readme-card">
                <div class="readme-card-num">04</div>
                <h3>通用信息</h3>
                <p>切换到「通用信息」标签页，可以查看：</p>
                <ul>
                  <li>通用请求参数说明</li>
                  <li>通用响应格式说明</li>
                </ul>
              </div>
            </div>

            <div class="content-section tips-card">
              <div class="tips-card-title">使用提示</div>
              <ul>
                <li>所有接口都需要携带鉴权 token</li>
                <li>请求参数需要放在 params 对象中</li>
                <li>响应格式统一，code 为 0 表示成功</li>
                <li>可以在「通用信息」标签页查看详细的请求和响应说明</li>
              </ul>
            </div>
          </div>

          <div
            v-if="currentApi"
            class="content-page api-detail"
            v-loading="apiDetailLoading"
            element-loading-text="正在加载接口详情..."
          >
            <div class="content-section page-header-card">
              <div class="page-header-main">
                <el-icon class="api-detail-icon"><Document /></el-icon>
                <div class="page-header-text">
                  <div class="page-header-label">接口</div>
                  <h1 class="api-action-name">{{ currentApi.action }}</h1>
                </div>
              </div>
              <el-button type="primary" plain size="small" :icon="DocumentCopy" @click="copyApiMarkdown">
                复制文档
              </el-button>
            </div>

            <div v-if="apiDetailError" class="api-detail-alert">
              <el-alert
                :title="apiDetailError"
                type="warning"
                :closable="false"
                show-icon
              />
            </div>

            <div v-if="apiDetail" class="api-detail-body">
              <section class="content-section">
              <h3 class="section-title">请求参数</h3>
              <div v-if="apiDetail?.paramModel">
                <p v-if="apiDetail.paramModel.basicProperty" class="basic-type-display">
                  类型：{{ getFullTypeName(apiDetail.paramModel) }}
                </p>
                <div
                  v-for="model in getAllModels(apiDetail.paramModel)"
                  :key="model.simpleName"
                  class="model-card"
                >
                  <h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}</h4>

                  <!-- 桌面端表格布局 -->
                  <el-table v-if="!isMobile" :data="model.fields" class="data-table">
                    <el-table-column prop="name" label="参数名" width="auto" />
                    <el-table-column label="类型" width="auto">
                      <template #default="scope">
                        <div class="type-display">
                          <template v-if="isGenericType(scope.row)">
                            <template v-if="isObjectType(scope.row)">
                              <a :href="'#model-' + getTypeName(scope.row)">{{
                                getTypeName(scope.row)
                              }}</a>
                            </template>
                            <template v-else>
                              {{ getTypeName(scope.row) }}
                            </template>
                            &lt;
                            <template
                              v-for="(param, index) in getGenericParams(scope.row)"
                              :key="index"
                            >
                              <template v-if="param.isObject">
                                <a :href="'#model-' + param.name">{{ param.name }}</a>
                              </template>
                              <template v-else>
                                {{ param.name }}
                              </template>
                              <template
                                v-if="index < getGenericParams(scope.row).length - 1"
                                >,</template
                              >
                            </template>
                            &gt;
                          </template>
                          <template v-else>
                            <template v-if="isObjectType(scope.row)">
                              <a :href="'#model-' + getTypeName(scope.row)">{{
                                getTypeName(scope.row)
                              }}</a>
                            </template>
                            <template v-else>
                              {{ getTypeName(scope.row) }}
                            </template>
                          </template>
                        </div>
                      </template>
                    </el-table-column>
                    <el-table-column prop="required" label="必填" width="auto">
                      <template #default="scope">
                        {{ scope.row.required ? "是" : "否" }}
                      </template>
                    </el-table-column>
                    <el-table-column prop="desc" label="说明">
                      <template #default="scope">
                        <div>
                          <div v-if="scope.row.desc">{{ scope.row.desc }}</div>
                          <div
                            v-if="scope.row.enumInfo && scope.row.enumInfo.properties"
                            style="margin-top: 8px"
                          >
                            <div
                              style="
                                font-weight: bolder;
                                color: #409eff;
                                margin-bottom: 4px;
                              "
                            >
                              枚举值：
                            </div>
                            <div
                              v-html="
                                scope.row.enumInfo.properties.map((item) => {
                                  return `${item.desc}(${item.value})`;
                                })
                              "
                              style="color: #606266"
                            ></div>
                          </div>
                          <div
                            v-if="
                              !scope.row.desc &&
                              !(scope.row.enumInfo && scope.row.enumInfo.properties)
                            "
                          >
                            -
                          </div>
                        </div>
                      </template>
                    </el-table-column>
                  </el-table>

                  <!-- 移动端卡片布局 -->
                  <div v-else class="mobile-field-list">
                    <el-collapse accordion>
                      <el-collapse-item v-for="field in model.fields" :key="field.name">
                        <template #title>
                          <div class="mobile-field-title">
                            <span class="field-name">{{ field.name }}</span>
                            <span v-if="field.required" class="field-required">必填</span>
                          </div>
                        </template>
                        <div class="mobile-field-content">
                          <div class="field-item">
                            <div class="field-label">类型:</div>
                            <div class="field-value type-display">
                              <template v-if="isGenericType(field)">
                                <template v-if="isObjectType(field)">
                                  <a :href="'#model-' + getTypeName(field)">{{
                                    getTypeName(field)
                                  }}</a>
                                </template>
                                <template v-else>
                                  {{ getTypeName(field) }}
                                </template>
                                &lt;
                                <template
                                  v-for="(param, index) in getGenericParams(field)"
                                  :key="index"
                                >
                                  <template v-if="param.isObject">
                                    <a :href="'#model-' + param.name">{{ param.name }}</a>
                                  </template>
                                  <template v-else>
                                    {{ param.name }}
                                  </template>
                                  <template
                                    v-if="index < getGenericParams(field).length - 1"
                                    >,</template
                                  >
                                </template>
                                &gt;
                              </template>
                              <template v-else>
                                <template v-if="isObjectType(field)">
                                  <a :href="'#model-' + getTypeName(field)">{{
                                    getTypeName(field)
                                  }}</a>
                                </template>
                                <template v-else>
                                  {{ getTypeName(field) }}
                                </template>
                              </template>
                            </div>
                          </div>
                          <div class="field-item" v-if="field.desc">
                            <div class="field-label">说明:</div>
                            <div class="field-value">{{ field.desc }}</div>
                          </div>
                          <div
                            class="field-item"
                            v-if="field.enumInfo && field.enumInfo.properties"
                          >
                            <div class="field-label">枚举值：</div>
                            <div class="field-value">
                              <div
                                v-html="
                                  field.enumInfo.properties.map((item) => {
                                    return `${item.desc}(${item.value})`;
                                  })
                                "
                              ></div>
                            </div>
                          </div>
                        </div>
                      </el-collapse-item>
                    </el-collapse>
                  </div>
                </div>
              </div>
              </section>

              <section class="content-section">
              <h3 class="section-title">请求响应</h3>
              <div v-if="apiDetail?.responseModel">
                <p v-if="apiDetail.responseModel.basicProperty" class="basic-type-display">
                  类型：{{ getFullTypeName(apiDetail.responseModel) }}
                </p>
                <div
                  v-for="model in getAllModels(apiDetail.responseModel)"
                  :key="model.simpleName"
                  class="model-card"
                >
                  <h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}</h4>
                  <!-- 桌面端表格布局 -->
                  <el-table v-if="!isMobile" :data="model.fields" class="data-table">
                    <el-table-column prop="name" label="参数名" width="auto" />
                    <el-table-column label="类型" width="auto">
                      <template #default="scope">
                        <div class="type-display">
                          <template v-if="isGenericType(scope.row)">
                            <template v-if="isObjectType(scope.row)">
                              <a :href="'#model-' + getTypeName(scope.row)">{{
                                getTypeName(scope.row)
                              }}</a>
                            </template>
                            <template v-else>
                              {{ getTypeName(scope.row) }}
                            </template>
                            &lt;
                            <template
                              v-for="(param, index) in getGenericParams(scope.row)"
                              :key="index"
                            >
                              <template v-if="param.isObject">
                                <a :href="'#model-' + param.name">{{ param.name }}</a>
                              </template>
                              <template v-else>
                                {{ param.name }}
                              </template>
                              <template
                                v-if="index < getGenericParams(scope.row).length - 1"
                                >,</template
                              >
                            </template>
                            &gt;
                          </template>
                          <template v-else>
                            <template v-if="isObjectType(scope.row)">
                              <a :href="'#model-' + getTypeName(scope.row)">{{
                                getTypeName(scope.row)
                              }}</a>
                            </template>
                            <template v-else>
                              {{ getTypeName(scope.row) }}
                            </template>
                          </template>
                        </div>
                      </template>
                    </el-table-column>
                    <el-table-column prop="desc" label="说明">
                      <template #default="scope">
                        <div>
                          <div v-if="scope.row.desc">{{ scope.row.desc }}</div>
                          <div
                            v-if="scope.row.enumInfo && scope.row.enumInfo.properties"
                            style="margin-top: 8px"
                          >
                            <div
                              style="
                                font-weight: bolder;
                                color: #409eff;
                                margin-bottom: 4px;
                              "
                            >
                              枚举值：
                            </div>
                            <div
                              v-html="
                                scope.row.enumInfo.properties.map((item) => {
                                  return `${item.desc}(${item.value})`;
                                })
                              "
                              style="color: #606266"
                            ></div>
                          </div>
                          <div
                            v-if="
                              !scope.row.desc &&
                              !(scope.row.enumInfo && scope.row.enumInfo.properties)
                            "
                          >
                            -
                          </div>
                        </div>
                      </template>
                    </el-table-column>
                  </el-table>

                  <!-- 移动端卡片布局 -->
                  <div v-else class="mobile-field-list">
                    <el-collapse accordion>
                      <el-collapse-item v-for="field in model.fields" :key="field.name">
                        <template #title>
                          <div class="mobile-field-title">
                            <span class="field-name">{{ field.name }}</span>
                          </div>
                        </template>
                        <div class="mobile-field-content">
                          <div class="field-item">
                            <div class="field-label">类型:</div>
                            <div class="field-value type-display">
                              <template v-if="isGenericType(field)">
                                <template v-if="isObjectType(field)">
                                  <a :href="'#model-' + getTypeName(field)">{{
                                    getTypeName(field)
                                  }}</a>
                                </template>
                                <template v-else>
                                  {{ getTypeName(field) }}
                                </template>
                                &lt;
                                <template
                                  v-for="(param, index) in getGenericParams(field)"
                                  :key="index"
                                >
                                  <template v-if="param.isObject">
                                    <a :href="'#model-' + param.name">{{ param.name }}</a>
                                  </template>
                                  <template v-else>
                                    {{ param.name }}
                                  </template>
                                  <template
                                    v-if="index < getGenericParams(field).length - 1"
                                    >,</template
                                  >
                                </template>
                                &gt;
                              </template>
                              <template v-else>
                                <template v-if="isObjectType(field)">
                                  <a :href="'#model-' + getTypeName(field)">{{
                                    getTypeName(field)
                                  }}</a>
                                </template>
                                <template v-else>
                                  {{ getTypeName(field) }}
                                </template>
                              </template>
                            </div>
                          </div>
                          <div class="field-item" v-if="field.desc">
                            <div class="field-label">说明:</div>
                            <div class="field-value">{{ field.desc }}</div>
                          </div>
                          <div
                            class="field-item"
                            v-if="field.enumInfo && field.enumInfo.properties"
                          >
                            <div class="field-label">枚举值：</div>
                            <div class="field-value">
                              <div
                                v-html="
                                  field.enumInfo.properties.map((item) => {
                                    return `${item.desc}(${item.value})`;
                                  })
                                "
                              ></div>
                            </div>
                          </div>
                        </div>
                      </el-collapse-item>
                    </el-collapse>
                  </div>
                </div>
              </div>
              </section>

              <section class="content-section">
              <h3 class="section-title">调用示例</h3>
              <el-tabs class="code-tabs">
                <el-tab-pane label="cURL">
                  <pre class="code-block">{{ generateCurlExample(currentApi) }}</pre>
                </el-tab-pane>
                <el-tab-pane label="JavaScript">
                  <pre class="code-block">{{ generateJsExample(currentApi) }}</pre>
                </el-tab-pane>
              </el-tabs>
              </section>
            </div>
          </div>
            </div>

            <div v-show="activeTab === 'common'" class="content-tab-panel">
          <div class="content-page common-info">
            <div class="content-section page-header-card">
              <div class="page-header-main">
                <div class="page-header-text">
                  <div class="page-header-label">说明</div>
                  <h1 class="page-hero-title">调用说明</h1>
                  <p class="page-hero-desc">所有接口通用的请求参数与响应格式</p>
                </div>
              </div>
            </div>

            <section class="content-section">
            <h3 class="section-title">通用请求参数</h3>
            <el-table
              :data="commonParams"
              class="data-table"
              :class="{ 'responsive-table': isMobile }"
            >
              <el-table-column prop="name" label="参数名" width="auto" />
              <el-table-column prop="required" label="必填" width="auto" />
              <el-table-column prop="desc" label="说明" />
            </el-table>
            </section>

            <section class="content-section">
            <h3 class="section-title">通用响应格式</h3>
            <el-table
              :data="commonResponse"
              class="data-table"
              :class="{ 'responsive-table': isMobile }"
            >
              <el-table-column prop="name" label="字段名" width="auto" />
              <el-table-column prop="desc" label="说明" />
            </el-table>
            </section>
          </div>
            </div>
          </div>
        </div>
      </template>
    </el-main>
  </el-container>

  <el-drawer
    v-model="showExportDrawer"
    title="导出文档"
    direction="rtl"
    size="480px"
    class="export-drawer"
  >
    <div class="export-module">
      <p class="export-description">
        导出接口文档为 Markdown 格式，支持导出全部或按需选择
      </p>

      <el-card shadow="never" class="quick-export-card">
        <template #header>
          <span class="card-header">快速导出</span>
        </template>
        <div class="quick-export-content">
          <p class="quick-export-desc">一键导出所有接口文档</p>
          <el-button
            type="primary"
            @click="downloadApiDocumentation"
            :loading="downloading"
            style="width: 100%"
          >
            {{ downloading ? "下载中..." : "下载全部接口文档" }}
          </el-button>
        </div>
      </el-card>

      <div class="export-content">
        <div class="export-section-title">
          <span class="card-header">按需导出</span>
          <p class="section-desc">选择需要导出的接口，生成自定义文档</p>
        </div>
        <div class="export-select-header">
          <el-input
            v-model="exportSearchQuery"
            placeholder="搜索接口"
            clearable
            :prefix-icon="Search"
          />
          <div class="select-actions">
            <el-button type="primary" @click="selectAllExportApis">全选</el-button>
            <el-button @click="deselectAllExportApis">取消全选</el-button>
            <span class="selected-count">
              已选择: {{ selectedApiIds.length }} / {{ totalExportApiCount }}
            </span>
          </div>
        </div>
        <div class="export-api-list">
          <el-tree
            ref="exportTreeRef"
            :data="exportTreeData"
            :props="exportTreeProps"
            show-checkbox
            node-key="id"
            :default-expand-all="false"
            :filter-node-method="filterExportNode"
            @check="handleExportTreeCheck"
          >
            <template #default="{ node, data }">
              <span class="export-tree-node">
                <el-icon v-if="data.isApi" class="api-icon"><Document /></el-icon>
                <el-icon v-else class="folder-icon"><Folder /></el-icon>
                <span class="node-label">{{ node.label }}</span>
              </span>
            </template>
          </el-tree>
        </div>
        <div class="export-actions">
          <el-button
            type="primary"
            @click="handleExportSelected"
            :loading="downloading"
            :disabled="selectedApiIds.length === 0"
            style="width: 100%"
          >
            {{ downloading ? "导出中..." : "导出所选文档" }}
          </el-button>
        </div>
      </div>
    </div>
  </el-drawer>
</template>

<script setup>
import { ref, onMounted, computed, watch, defineComponent, h } from "vue";
import axios from "axios";
import { ElMessage } from "element-plus";
import { DocumentCopy, Close, Document, Folder, ArrowRight, ArrowLeft, HomeFilled, Search, Download, Menu } from "@element-plus/icons-vue";

const activeMenuIndex = computed(() => currentApi.value?.uniqueId ?? "");

// 统计节点下接口总数（含子目录）
const getNodeApiCount = (node) => {
  let count = node.apis?.length || 0;
  (node.children || []).forEach((child) => {
    count += getNodeApiCount(child);
  });
  return count;
};

// 递归菜单节点组件（用于处理无限级嵌套）
const MenuTreeNode = defineComponent({
  name: "MenuTreeNode",
  props: {
    node: {
      type: Object,
      required: true,
    },
  },
  emits: ["go-to-api"],
  setup(props, { emit, slots }) {
    const handleGoToApi = (api) => {
      emit("go-to-api", api);
    };

    return () => {
      const { node } = props;

      // 未分组的API直接显示为菜单项
      if (node.isUngrouped) {
        return h(
          "el-menu-item",
          {
            index: node.key,
            onClick: () => {
              handleGoToApi(node.apis[0]);
            },
          },
          () => node.displayName
        );
      }

      // 分组的API显示为子菜单
      return h(
        "el-sub-menu",
        {
          index: node.key,
        },
        {
          title: () => h("span", node.displayName),
          default: () => [
            // 显示该节点下的API
            ...(node.apis || []).map((api) =>
              h(
                "el-menu-item",
                {
                  key: api.uniqueId,
                  index: api.uniqueId,
                  onClick: () => {
                    handleGoToApi(api);
                  },
                },
                () => getActionDisplayName(api.action, node.fullPath)
              )
            ),
            // 递归渲染子节点
            ...(node.children || []).map((child) =>
              h(MenuTreeNode, {
                key: child.key,
                node: child,
                "onGo-to-api": handleGoToApi,
              })
            ),
          ],
        }
      );
    };
  },
});

const apis = ref([]);
const currentApi = ref(null);
const apiDetail = ref(null);
const searchQuery = ref("");
const isMobile = ref(false);
const showMenu = ref(false);
const currentPath = ref([]); // 当前路径，用于记录层级
const currentPathKeys = ref([]); // 当前路径的key数组
const downloading = ref(false); // 下载状态
const apiDetailsCache = ref({}); // API详情缓存
const activeTab = ref("docs"); // 当前激活的标签页
const selectedApiIds = ref([]); // 选中的API ID列表
const exportSearchQuery = ref(""); // 导出搜索查询
const exportTreeRef = ref(null); // 导出树引用
const loading = ref(true); // 接口列表加载状态（初始为true，减少闪烁）
const loadError = ref(null); // 加载错误信息（接口列表加载失败）
const apiDetailLoading = ref(false); // 接口详情加载状态
const apiDetailError = ref(null); // 接口详情加载错误
const exportTreeProps = {
  children: "children",
  label: "label",
};

const hostUrl = ref(import.meta.env.VITE_API_URL || "/api");
const showExportDrawer = ref(false);

// 监听搜索，如果有搜索则自动返回根级别显示所有匹配结果
watch(searchQuery, (newVal) => {
  if (newVal && newVal.trim()) {
    // 搜索时自动返回根级别，显示所有匹配结果
    currentPath.value = [];
    currentPathKeys.value = [];
  }
});

// IndexedDB 缓存工具
const DB_NAME = "api-docs-cache";
const DB_VERSION = 4;
const STORE_NAME = "api-list";

// 初始化 IndexedDB（支持版本兼容）
const initDB = () => {
  return new Promise((resolve, reject) => {
    const request = indexedDB.open(DB_NAME, DB_VERSION);

    request.onerror = (event) => {
      const error = event.target.error;
      // 如果是版本错误，尝试使用当前版本打开
      if (error && error.name === "VersionError") {
        // 先打开数据库获取当前版本
        const checkRequest = indexedDB.open(DB_NAME);
        checkRequest.onsuccess = () => {
          const currentVersion = checkRequest.result.version;
          checkRequest.result.close();

          // 使用当前版本打开（不触发升级）
          const currentRequest = indexedDB.open(DB_NAME, currentVersion);
          currentRequest.onsuccess = () => resolve(currentRequest.result);
          currentRequest.onerror = () => reject(currentRequest.error);
        };
        checkRequest.onerror = () => reject(checkRequest.error);
      } else {
        reject(error);
      }
    };

    request.onsuccess = () => resolve(request.result);

    request.onupgradeneeded = (event) => {
      const db = event.target.result;

      if (!db.objectStoreNames.contains(STORE_NAME)) {
        db.createObjectStore(STORE_NAME);
      }
    };

    request.onblocked = () => {
      console.warn("Database upgrade blocked");
    };
  });
};

// 从 IndexedDB 获取缓存的接口列表
const getCachedApiList = async () => {
  try {
    const db = await initDB();
    return new Promise((resolve, reject) => {
      const transaction = db.transaction([STORE_NAME], "readonly");
      const store = transaction.objectStore(STORE_NAME);
      const request = store.get("api-list");
      request.onsuccess = () => resolve(request.result || null);
      request.onerror = () => reject(request.error);
    });
  } catch (error) {
    console.error("Failed to get cached API list:", error);
    return null;
  }
};

// 将接口列表保存到 IndexedDB
const saveApiListToCache = async (apiList) => {
  try {
    const db = await initDB();
    return new Promise((resolve, reject) => {
      const transaction = db.transaction([STORE_NAME], "readwrite");
      const store = transaction.objectStore(STORE_NAME);
      const request = store.put(apiList, "api-list");
      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  } catch (error) {
    console.error("Failed to save API list to cache:", error);
  }
};

const commonParams = [
  { name: "action", desc: "请求的服务接口名称", required: "是" },
  { name: "token", desc: "携带的鉴权token", required: "是" },
  { name: "params", desc: "业务参数对象", required: "是" },
];

const commonResponse = [
  { name: "code", desc: "状态码, 0表示成功，103表示鉴权失败" },
  { name: "msg", desc: "错误信息" },
  { name: "data", desc: "数据内容，对象或列表" },
];

// 处理接口列表数据
const processApiList = (apiData) => {
  // 展开API列表，如果一个API包含多个action，则分开显示
  const expandedApis = [];
  apiData.forEach((api) => {
    // 如果action是数组，展开成多个API项
    if (Array.isArray(api.action)) {
      api.action.forEach((action, index) => {
        expandedApis.push({
          ...api,
          action: action,
          uniqueId: `${api.id}_${index}`, // 生成唯一ID
          originalId: api.id, // 保留原始ID用于获取详情
        });
      });
    } else {
      // 单个action，直接添加
      expandedApis.push({
        ...api,
        uniqueId: `${api.id}_0`, // 生成唯一ID
        originalId: api.id, // 保留原始ID用于获取详情
      });
    }
  });

  // 按action排序
  return expandedApis.sort((a, b) => a.action.localeCompare(b.action));
};



onMounted(async () => {
  checkDeviceType();
  window.addEventListener("resize", checkDeviceType);

  loading.value = true; // 先显示加载状态，避免显示空白页面
  loadError.value = null;

  // 先从缓存获取接口列表
  let cachedApiList = null;
  try {
    cachedApiList = await getCachedApiList();
    if (cachedApiList) {
      // 使用缓存数据先渲染
      apis.value = processApiList(cachedApiList);
      // 有缓存数据后，立即隐藏加载状态，让用户看到内容
      loading.value = false;

      // 检查URL是否包含API id参数
      const urlParams = new URLSearchParams(window.location.search);
      const id = urlParams.get("id");
      if (id) {
        const apiToShow = findApiById(id);
        if (apiToShow) {
          showApiDetail(apiToShow);
        }
      }
    }
    // 如果没有缓存数据，继续显示加载状态，等待请求完成
  } catch (error) {
    console.error("Failed to load cached API list:", error);
    // 缓存加载失败，继续显示加载状态，等待请求完成
  }

  // 然后请求最新的接口列表（后台无感刷新）
  try {
    const response = await axios.get(hostUrl.value, {
      params: {
        action: "getActionList",
      },
    });

    // 处理并保存最新的接口列表
    const processedApis = processApiList(response.data.data);
    apis.value = processedApis;

    // 保存到缓存
    await saveApiListToCache(response.data.data);

    // 检查URL是否包含API id参数
    const urlParams = new URLSearchParams(window.location.search);
    const id = urlParams.get("id");
    if (id) {
      const apiToShow = findApiById(id);
      if (apiToShow) {
        showApiDetail(apiToShow);
      }
    }
  } catch (error) {
    console.error("Failed to fetch API list:", error);
    // 如果请求失败且没有缓存数据，显示错误
    if (!cachedApiList) {
      loadError.value =
        error.response?.data?.msg || error.message || "获取接口列表失败，请稍后重试";
    } else {
      // 有缓存数据，只提示用户使用的是缓存数据（静默提示，不干扰用户）
      ElMessage.warning("获取最新接口列表失败，已使用缓存数据");
    }
  } finally {
    // 确保最终隐藏加载状态（如果没有缓存数据，这里会隐藏；如果有缓存数据，已经在上面隐藏了）
    loading.value = false;
  }

});

// 根据id查找API
const findApiById = (id) => {
  return apis.value.find((a) => a.uniqueId === id || a.originalId === id) || null;
};

// 更新URL参数
const updateUrlParameter = (id) => {
  const url = new URL(window.location);
  if (id) {
    url.searchParams.set("id", id);
  } else {
    url.searchParams.delete("id");
  }
  window.history.pushState({}, "", url);
};

// 路由到首页
const goHome = () => {
  currentApi.value = null;
  currentPath.value = [];
  currentPathKeys.value = [];
  updateUrlParameter(null);
};

// 路由到指定API
const goToApi = (api) => {
  showApiDetail(api);
  updateUrlParameter(api.uniqueId);
};

const checkDeviceType = () => {
  isMobile.value = window.innerWidth <= 768;
  showMenu.value = !isMobile.value;
};

const toggleMenu = () => {
  showMenu.value = !showMenu.value;
};

const showApiDetail = async (api) => {
  currentApi.value = api;
  apiDetail.value = null; // 清空之前的详情
  apiDetailError.value = null; // 清空错误信息
  apiDetailLoading.value = true;
  try {
    const response = await axios.get(hostUrl.value, {
      params: {
        action: "getActionDetail",
        id: api.originalId || api.id,
      },
    });
    apiDetail.value = response.data.data;
  } catch (error) {
    console.error("Failed to fetch API detail:", error);
    // 如果接口详情加载失败，尝试从接口列表中获取基本信息
    if (api) {
      // 使用接口列表中的基本信息作为详情
      apiDetail.value = {
        action: api.action,
        paramModel: null,
        responseModel: null,
        // 可以添加其他从接口列表中获取的字段
      };
      apiDetailError.value = "获取接口详情失败，已使用接口列表中的基本信息";
      ElMessage.warning("获取接口详情失败，已使用接口列表中的基本信息");
    } else {
      apiDetailError.value =
        error.response?.data?.msg || error.message || "获取接口详情失败";
    }
  } finally {
    apiDetailLoading.value = false;
  }
};

const generateCurlExample = (api) => {
  // 获取必传参数
  const requiredParams =
    apiDetail.value?.paramModel?.fields
      ?.filter((field) => field.required)
      ?.reduce((acc, field) => {
        acc[field.name] = getExampleValue(field);
        return acc;
      }, {}) || {};

  return `curl -X POST 'API_URL' \\
  -H 'Content-Type: application/json' \\
  -d '{
    "action": "${api.action}",
    "token": "YOUR_TOKEN",
    "params": {${
      Object.entries(requiredParams)
        .map(([key, value]) => '\n      "' + key + '": ' + JSON.stringify(value))
        .join(",") || ""
    }
    }
  }'`;
};

const generateJsExample = (api) => {
  // 获取必传参数
  const requiredParams =
    apiDetail.value?.paramModel?.fields
      ?.filter((field) => field.required)
      ?.reduce((acc, field) => {
        acc[field.name] = getExampleValue(field);
        return acc;
      }, {}) || {};

  return `// 使用 axios
axios.post('API_URL', {
  action: '${api.action}',
  token: 'YOUR_TOKEN',
  params: {${
    Object.entries(requiredParams)
      .map(([key, value]) => "\n    " + key + ": " + JSON.stringify(value))
      .join(",") || ""
  }
  }
})
.then(response => {
  console.log(response.data);
})
.catch(error => {
  console.error(error);
});`;
};

// 根据类型生成示例值
const getExampleValue = (field) => {
  if (!field) return null;

  if (field.typeName === "String") return "example";
  if (field.typeName === "Integer" || field.typeName === "Long") return 0;
  if (field.typeName === "Double" || field.typeName === "Float") return 0.0;
  if (field.typeName === "Boolean") return false;
  if (field.typeName === "Date") return "2023-01-01";
  if (field.typeName === "DateTime") return "2023-01-01 00:00:00";
  if (field.typeName === "List" || field.typeName === "Set" || field.typeName === "Array")
    return [];
  if (field.typeName === "Map" || !field.basicProperty) return {};

  return null;
};

const isModelGroup = (model) => {
  return (
    model &&
    !model.basicProperty &&
    Array.isArray(model.fields) &&
    model.fields.length > 0
  );
};

const getModelDisplayName = (model) => {
  if (!model) return "";
  const containerTypes = ["List", "Set", "Map", "Array"];
  if (model.simpleName && !containerTypes.includes(model.simpleName)) {
    return model.simpleName;
  }
  if (model.className) {
    const shortName = model.className.split(".").pop();
    if (shortName) return shortName;
  }
  return model.simpleName || "";
};

const hasNestedModelContent = (model) => {
  if (!model) return false;
  if (isModelGroup(model)) return true;
  return (model.parametricModels || []).some((item) => hasNestedModelContent(item));
};

const getAllModels = (model, parentInfo) => {
  if (!model) return [];

  const models = [];

  if (isModelGroup(model)) {
    models.push(Object.assign({ parentInfo }, model));
  }

  const collectFromFields = (fields) => {
    (fields || []).forEach((field) => {
      if (field.parametricModels?.length) {
        field.parametricModels.forEach((parametricModel) => {
          models.push(...getAllModels(parametricModel));
        });
      } else if (field.model?.parametricModels?.length) {
        field.model.parametricModels.forEach((parametricModel) => {
          models.push(...getAllModels(parametricModel));
        });
      } else if (field.model && !field.model.basicProperty) {
        models.push(...getAllModels(field.model));
      }
    });
  };

  if (isModelGroup(model)) {
    collectFromFields(model.fields);
  }

  // List / Map 等 basicProperty 泛型容器，继续展开泛型参数中的模型
  if (model.parametricModels?.length) {
    model.parametricModels.forEach((parametricModel, index) => {
      models.push(
        ...getAllModels(parametricModel, {
          index,
          length: model.parametricModels.length,
          simpleName: model.simpleName,
        })
      );
    });
  }

  return models;
};

// 是否应显示模型锚点链接（basicProperty 基础类型不跳转，泛型参数中的对象类型可跳转）
const isObjectType = (field) => {
  if (!field) return false;
  // 泛型容器（List/Map 等）本身不跳转，由 getGenericParams 处理泛型参数链接
  if (field.basicProperty && isGenericType(field)) return false;
  if (field.basicProperty) return false;
  if (field.model?.basicProperty && !field.model?.parametricModels?.length) return false;
  if (field.model) return hasNestedModelContent(field.model);
  return true;
};

const isGenericType = (field) => {
  return field && field.parametricModels && field.parametricModels.length > 0;
};

const getTypeName = (field) => {
  if (!field) {
    return "";
  }
  return field.typeName || field.simpleName || "";
};

const getGenericParams = (field) => {
  if (!field || !field.parametricModels) {
    return [];
  }
  return field.parametricModels
    .filter((item) => !!item)
    .map((item) => ({
      name: getModelDisplayName(item),
      isObject: hasNestedModelContent(item),
    }));
};

// 获取完整的类型名称（包括泛型参数）
const getFullTypeName = (field) => {
  if (!field) {
    return "";
  }

  const baseType = getTypeName(field);

  // 如果是泛型类型，添加泛型参数
  if (isGenericType(field)) {
    const genericParams = getGenericParams(field)
      .map((param) => param.name)
      .join(", ");
    return `${baseType}<${genericParams}>`;
  }

  return baseType;
};

// 获取action的显示名称（去掉上级路径）
const getActionDisplayName = (action, parentPath) => {
  if (!action || typeof action !== "string") return action;
  if (!parentPath) return action;
  const prefix = parentPath + ".";
  if (action.startsWith(prefix)) {
    return action.substring(prefix.length);
  }
  return action;
};

// 解析点分路径，构建目录/文件树（最后一段为接口，其余为目录）
const buildTree = (paths) => {
  const root = {};

  paths.forEach((path) => {
    const parts = path.split(".");
    let current = root;

    parts.forEach((part, index) => {
      const isFile = index === parts.length - 1;

      if (!current[part]) {
        current[part] = isFile
          ? { type: "file" }
          : { type: "dir", children: {} };
      }

      if (!isFile && current[part].type !== "dir") {
        throw new Error(`冲突: "${part}" 不能同时是文件和目录`);
      }

      if (!isFile) {
        current = current[part].children;
      }
    });
  });

  return root;
};

// 将 buildTree 结果转为侧边栏节点，并挂载 API 对象
const convertTreeToUiNodes = (treeObj, parentPath, apiMap) => {
  return Object.entries(treeObj)
    .filter(([, node]) => node.type === "dir")
    .map(([name, node]) => {
      const fullPath = parentPath ? `${parentPath}.${name}` : name;
      const children = [];
      const apis = [];

      Object.entries(node.children).forEach(([part, child]) => {
        if (child.type === "file") {
          const api = apiMap.get(`${fullPath}.${part}`);
          if (api) apis.push(api);
        } else if (child.type === "dir") {
          children.push(...convertTreeToUiNodes({ [part]: child }, fullPath, apiMap));
        }
      });

      return {
        key: fullPath,
        displayName: name,
        fullPath,
        children,
        apis,
      };
    })
    .sort((a, b) => {
      if (a.children.length > 0 && b.children.length === 0) return -1;
      if (a.children.length === 0 && b.children.length > 0) return 1;
      return a.displayName.localeCompare(b.displayName);
    });
};

// 按点分路径分类接口（有层级 / 未分组）
const classifyApisByPath = (apiList) => {
  const ungrouped = [];
  const groupedApis = [];

  apiList.forEach((api) => {
    if (!api.action || typeof api.action !== "string") {
      ungrouped.push(api);
      return;
    }

    const parts = api.action.split(".");
    if (parts.length <= 1 || parts[0] === "") {
      ungrouped.push(api);
    } else {
      groupedApis.push(api);
    }
  });

  return { groupedApis, ungrouped };
};

// 导出树节点排序：目录在前，接口在后，同类型按名称排序
const sortExportNodes = (nodes) => {
  return nodes.sort((a, b) => {
    if (!a.isApi && b.isApi) return -1;
    if (a.isApi && !b.isApi) return 1;
    return a.label.localeCompare(b.label);
  });
};

// 将 buildTree 结果转为导出树节点（el-tree 格式）
const convertTreeToExportNodes = (treeObj, parentPath, apiMap) => {
  const result = [];

  Object.entries(treeObj).forEach(([name, node]) => {
    if (node.type === "dir") {
      const fullPath = parentPath ? `${parentPath}.${name}` : name;
      const children = [];

      Object.entries(node.children).forEach(([part, child]) => {
        if (child.type === "file") {
          const api = apiMap.get(`${fullPath}.${part}`);
          if (api) {
            children.push({
              id: api.uniqueId,
              label: getActionDisplayName(api.action, fullPath),
              isApi: true,
              api,
            });
          }
        } else if (child.type === "dir") {
          const subNodes = convertTreeToExportNodes({ [part]: child }, fullPath, apiMap);
          children.push(...subNodes);
        }
      });

      result.push({
        id: fullPath,
        label: name,
        isApi: false,
        children: sortExportNodes(children),
      });
    } else if (node.type === "file") {
      const actionPath = parentPath ? `${parentPath}.${name}` : name;
      const api = apiMap.get(actionPath);
      if (api) {
        result.push({
          id: api.uniqueId,
          label: api.action,
          isApi: true,
          api,
        });
      }
    }
  });

  return sortExportNodes(result);
};

// 构建导出树（支持无限级）
const buildExportTree = (apiList) => {
  const { groupedApis, ungrouped } = classifyApisByPath(apiList);
  const result = [];

  if (groupedApis.length > 0) {
    try {
      const tree = buildTree(groupedApis.map((api) => api.action));
      const apiMap = new Map(groupedApis.map((api) => [api.action, api]));
      result.push(...convertTreeToExportNodes(tree, "", apiMap));
    } catch (error) {
      console.error("导出树路径解析冲突:", error);
      groupedApis.forEach((api) => ungrouped.push(api));
    }
  }

  ungrouped.forEach((api) => {
    result.push({
      id: api.uniqueId,
      label: api.action,
      isApi: true,
      api,
    });
  });

  return sortExportNodes(result);
};

// 构建树形结构（支持无限级）
const buildApiTree = (apiList) => {
  const { groupedApis, ungrouped } = classifyApisByPath(apiList);

  let treeArray = [];
  if (groupedApis.length > 0) {
    try {
      const tree = buildTree(groupedApis.map((api) => api.action));
      const apiMap = new Map(groupedApis.map((api) => [api.action, api]));
      treeArray = convertTreeToUiNodes(tree, "", apiMap);
    } catch (error) {
      console.error("接口路径解析冲突:", error);
      groupedApis.forEach((api) => ungrouped.push(api));
    }
  }

  // 未分组的API也添加到结果中
  ungrouped.forEach((api) => {
    treeArray.push({
      key: api.uniqueId,
      displayName: api.action,
      fullPath: "",
      children: [],
      apis: [api], // 将api放入apis数组中，保持结构一致
      isUngrouped: true, // 标记为未分组
    });
  });

  return treeArray;
};

// 搜索匹配函数（大小写不敏感）
const matchesSearch = (text, query) => {
  if (!text || !query) return false;
  return text.toLowerCase().includes(query.toLowerCase());
};

// 过滤后的API列表（搜索时使用）
const filteredApis = computed(() => {
  if (!searchQuery.value) {
    return apis.value;
  }

  const query = searchQuery.value.toLowerCase();
  return apis.value.filter((api) => {
    if (!api.action) return false;
    return matchesSearch(api.action, query);
  });
});

// API树形结构（根据是否有搜索决定使用原始数据还是过滤后的数据）
const apiTree = computed(() => {
  // 如果有搜索，使用过滤后的API列表构建树；否则使用原始API列表
  const apiList = searchQuery.value ? filteredApis.value : apis.value;
  return buildApiTree(apiList);
});

// 过滤API树（保持兼容性，实际已通过 apiTree 实现）
const filteredApiTree = computed(() => {
  return apiTree.value;
});

// 根据当前路径获取当前层级要显示的节点和API
const currentLevelNodes = computed(() => {
  // 根据路径找到当前节点
  let currentNode = apiTree.value;
  let currentParentNode = null;

  for (const key of currentPathKeys.value) {
    const found = currentNode.find((node) => node.key === key);
    if (found) {
      currentParentNode = found;
      currentNode = found.children || [];
    } else {
      return [];
    }
  }

  // 如果当前父节点只有API没有子节点，返回空数组（API由 currentLevelApis 处理）
  if (
    currentParentNode &&
    currentParentNode.apis.length > 0 &&
    currentNode.length === 0
  ) {
    return [];
  }

  // 如果有搜索，由于已经通过 filteredApis 过滤了数据并重新构建树，所以直接返回当前节点即可
  // 搜索只匹配 action，不匹配节点名称
  if (searchQuery.value) {
    // 树中已经只包含匹配的 API，直接返回
    return currentNode;
  }

  return currentNode;
});

// 当前层级的API（用于显示当前节点下的API列表，即使该节点有子节点也会显示）
const currentLevelApis = computed(() => {
  if (currentPathKeys.value.length === 0) return [];

  let currentNode = apiTree.value;
  let currentParentNode = null;

  for (const key of currentPathKeys.value) {
    const found = currentNode.find((node) => node.key === key);
    if (found) {
      currentParentNode = found;
      currentNode = found.children || [];
    } else {
      return [];
    }
  }

  // 如果当前父节点有API，返回这些API（即使该节点有子节点也会显示）
  if (currentParentNode && currentParentNode.apis.length > 0) {
    // 如果有搜索，由于已经通过 filteredApis 过滤了数据，所以 apis 中已经只包含匹配的 API
    // 搜索只匹配 action，不匹配节点名称
    if (searchQuery.value) {
      const queryLower = searchQuery.value.toLowerCase();
      return currentParentNode.apis.sort((a, b) => {
        // 排序：精确匹配优先
        const aMatch = a.action.toLowerCase() === queryLower;
        const bMatch = b.action.toLowerCase() === queryLower;
        if (aMatch && !bMatch) return -1;
        if (!aMatch && bMatch) return 1;
        return a.action.localeCompare(b.action);
      });
    }
    return currentParentNode.apis;
  }

  return [];
});

// 进入分组
const enterGroup = (node) => {
  currentPath.value.push(node.displayName);
  currentPathKeys.value.push(node.key);

  // 自动遍历：如果当前目录没有接口且只有一个子目录，自动进入下一个目录
  autoNavigateToNextGroup();
};

// 自动遍历到下一个目录（如果当前目录没有接口且只有一个子目录）
const autoNavigateToNextGroup = () => {
  // 根据路径找到当前节点
  let currentNode = apiTree.value;
  let currentParentNode = null;

  for (const key of currentPathKeys.value) {
    const found = currentNode.find((node) => node.key === key);
    if (found) {
      currentParentNode = found;
      currentNode = found.children || [];
    } else {
      return;
    }
  }

  // 如果当前目录没有API且只有一个子目录，自动进入该子目录
  // 循环直到找到有API的目录或者有多个子目录的目录
  while (
    currentParentNode &&
    currentParentNode.apis.length === 0 &&
    currentNode.length === 1
  ) {
    const nextNode = currentNode[0];
    currentPath.value.push(nextNode.displayName);
    currentPathKeys.value.push(nextNode.key);

    // 更新当前节点
    currentParentNode = nextNode;
    currentNode = nextNode.children || [];
  }
};

// 返回上一级
const goBack = () => {
  if (currentPath.value.length > 0) {
    currentPath.value.pop();
    currentPathKeys.value.pop();
  }
};

// 导航到指定路径
const navigateToPath = (index) => {
  // 截取到指定索引的路径
  currentPath.value = currentPath.value.slice(0, index + 1);
  currentPathKeys.value = currentPathKeys.value.slice(0, index + 1);
};

// 获取当前节点API的显示名称
const getCurrentNodeApiDisplayName = (api) => {
  if (!api || !api.action) return api.action || "";

  // 找到当前节点的 fullPath
  let currentNode = apiTree.value;
  let currentParentNode = null;

  for (const key of currentPathKeys.value) {
    const found = currentNode.find((node) => node.key === key);
    if (found) {
      currentParentNode = found;
      currentNode = found.children || [];
    } else {
      break;
    }
  }

  if (currentParentNode && currentParentNode.fullPath) {
    return getActionDisplayName(api.action, currentParentNode.fullPath);
  }

  return api.action;
};

// 下载接口文档
const downloadApiDocumentation = async () => {
  downloading.value = true;
  try {
    // 直接使用接口列表数据，不请求详情
    const allApiDetails = apis.value.map((api) => ({
      api,
      detail: api, // 使用接口列表数据本身作为详情
    }));

    // 生成Markdown文档
    const markdown = generateMarkdownDocumentation(allApiDetails);

    // 下载文件
    const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" });
    const url = URL.createObjectURL(blob);
    const link = document.createElement("a");
    link.href = url;
    link.download = `API文档_${new Date().toISOString().split("T")[0]}.md`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(url);
  } catch (error) {
    console.error("Failed to download documentation:", error);
    alert("下载失败，请稍后重试");
  } finally {
    downloading.value = false;
  }
};

// 生成Markdown文档内容
const generateMarkdownDocumentation = (allApiDetails) => {
  let markdown = "# API 接口文档\n\n";
  markdown += `生成时间: ${new Date().toLocaleString("zh-CN")}\n\n`;
  markdown += `总计接口数: ${allApiDetails.length}\n\n`;
  markdown += "---\n\n";

  // 通用请求参数
  markdown += "## 通用请求参数\n\n";
  markdown += "| 参数名| 必填 | 说明  |\n";
  markdown += "|--------|------|----------|\n";
  commonParams.forEach((param) => {
    markdown += `| ${param.name} | ${param.required} | ${param.desc} |\n`;
  });
  markdown += "\n";

  // 通用响应格式
  markdown += "## 通用响应格式\n\n";
  markdown += "| 字段名 | 说明 |\n";
  markdown += "|--------|------|\n";
  commonResponse.forEach((field) => {
    markdown += `| ${field.name} | ${field.desc} |\n`;
  });
  markdown += "\n---\n\n";

  // 接口详情
  markdown += "## 接口详情\n\n";
  allApiDetails.forEach(({ api, detail }, index) => {
    markdown += `### ${index + 1}. ${api.action}\n\n`;

    if (detail) {
      // 请求参数
      if (detail.paramModel) {
        markdown += "#### 请求参数\n\n";
        if (detail.paramModel.basicProperty) {
          markdown += `类型：${getFullTypeName(detail.paramModel)}\n\n`;
        }
        const paramModels = getAllModels(detail.paramModel);
        if (paramModels.length > 0) {
          paramModels.forEach((model) => {
            markdown += `**${getModelDisplayName(model)}**\n\n`;
            markdown += "| 参数名 | 类型 | 必填 | 说明 |\n";
            markdown += "|--------|------|------|----------|\n";
            (model.fields || []).forEach((field) => {
              const typeName = getFullTypeName(field);
              const required = field.required ? "是" : "否";
              let desc = field.desc || "-";

              if (
                field.enumInfo &&
                field.enumInfo.properties &&
                field.enumInfo.properties.length > 0
              ) {
                const enumValues = field.enumInfo.properties
                  .map((item) => `${item.desc}(${item.value})`)
                  .join("、");
                desc =
                  desc !== "-"
                    ? `${desc}；枚举值：${enumValues}`
                    : `枚举值：${enumValues}`;
              }

              markdown += `| ${field.name} | ${typeName} | ${required} | ${desc} |\n`;
            });
            markdown += "\n";
          });
        } else if (!detail.paramModel.basicProperty) {
          markdown += "无参数\n\n";
        }
      }

      // 请求响应
      if (detail.responseModel) {
        markdown += "#### 请求响应\n\n";
        if (detail.responseModel.basicProperty) {
          markdown += `类型：${getFullTypeName(detail.responseModel)}\n\n`;
        }
        const responseModels = getAllModels(detail.responseModel);
        if (responseModels.length > 0) {
          responseModels.forEach((model) => {
            markdown += `**${getModelDisplayName(model)}**\n\n`;
            markdown += "| 字段名 | 类型 | 说明 |\n";
            markdown += "|--------|------|------|\n";
            (model.fields || []).forEach((field) => {
              const typeName = getFullTypeName(field);
              let desc = field.desc || "-";

              if (
                field.enumInfo &&
                field.enumInfo.properties &&
                field.enumInfo.properties.length > 0
              ) {
                const enumValues = field.enumInfo.properties
                  .map((item) => `${item.desc}(${item.value})`)
                  .join("、");
                desc =
                  desc !== "-"
                    ? `${desc}；枚举值：${enumValues}`
                    : `枚举值：${enumValues}`;
              }

              markdown += `| ${field.name} | ${typeName} | ${desc} |\n`;
            });
            markdown += "\n";
          });
        } else if (!detail.responseModel.basicProperty) {
          markdown += "无响应数据\n\n";
        }
      } else {
        markdown += "#### 请求响应\n\n";
        markdown += "无响应数据\n\n";
      }
    } else {
      markdown += "> 无法获取接口详情\n\n";
    }

    markdown += "---\n\n";
  });

  return markdown;
};

// 生成单个接口的Markdown文档
const generateSingleApiMarkdown = (api, detail) => {
  let markdown = `# ${api.action}\n\n`;
  markdown += `生成时间: ${new Date().toLocaleString("zh-CN")}\n\n`;
  markdown += "---\n\n";

  // 通用请求参数
  markdown += "## 通用请求参数\n\n";
  markdown += "| 参数名| 必填 | 说明  |\n";
  markdown += "|--------|------|----------|\n";
  commonParams.forEach((param) => {
    markdown += `| ${param.name} | ${param.required} | ${param.desc} |\n`;
  });
  markdown += "\n";

  // 通用响应格式
  markdown += "## 通用响应格式\n\n";
  markdown += "| 字段名 | 说明 |\n";
  markdown += "|--------|------|\n";
  commonResponse.forEach((field) => {
    markdown += `| ${field.name} | ${field.desc} |\n`;
  });
  markdown += "\n---\n\n";

  // 接口详情
  markdown += `## ${api.action}\n\n`;

  if (detail) {
    // 请求参数
    if (detail.paramModel) {
      markdown += "### 请求参数\n\n";
      if (detail.paramModel.basicProperty) {
        markdown += `类型：${getFullTypeName(detail.paramModel)}\n\n`;
      }
      const paramModels = getAllModels(detail.paramModel);
      if (paramModels.length > 0) {
        paramModels.forEach((model) => {
          markdown += `**${getModelDisplayName(model)}**\n\n`;
          markdown += "| 参数名 | 类型 | 必填 | 说明 |\n";
          markdown += "|--------|------|------|----------|\n";
          (model.fields || []).forEach((field) => {
            const typeName = getFullTypeName(field);
            const required = field.required ? "是" : "否";
            let desc = field.desc || "-";

            if (
              field.enumInfo &&
              field.enumInfo.properties &&
              field.enumInfo.properties.length > 0
            ) {
              const enumValues = field.enumInfo.properties
                .map((item) => `${item.desc}(${item.value})`)
                .join("、");
              desc =
                desc !== "-" ? `${desc}；枚举值：${enumValues}` : `枚举值：${enumValues}`;
            }

            markdown += `| ${field.name} | ${typeName} | ${required} | ${desc} |\n`;
          });
          markdown += "\n";
        });
      } else if (!detail.paramModel.basicProperty) {
        markdown += "无参数\n\n";
      }
    }

    // 请求响应
    if (detail.responseModel) {
      markdown += "### 请求响应\n\n";
      if (detail.responseModel.basicProperty) {
        markdown += `类型：${getFullTypeName(detail.responseModel)}\n\n`;
      }
      const responseModels = getAllModels(detail.responseModel);
      if (responseModels.length > 0) {
        responseModels.forEach((model) => {
          markdown += `**${getModelDisplayName(model)}**\n\n`;
          markdown += "| 字段名 | 类型 | 说明 |\n";
          markdown += "|--------|------|------|\n";
          (model.fields || []).forEach((field) => {
            const typeName = getFullTypeName(field);
            let desc = field.desc || "-";

            if (
              field.enumInfo &&
              field.enumInfo.properties &&
              field.enumInfo.properties.length > 0
            ) {
              const enumValues = field.enumInfo.properties
                .map((item) => `${item.desc}(${item.value})`)
                .join("、");
              desc =
                desc !== "-" ? `${desc}；枚举值：${enumValues}` : `枚举值：${enumValues}`;
            }

            markdown += `| ${field.name} | ${typeName} | ${desc} |\n`;
          });
          markdown += "\n";
        });
      } else if (!detail.responseModel.basicProperty) {
        markdown += "无响应数据\n\n";
      }
    } else {
      markdown += "### 请求响应\n\n";
      markdown += "无响应数据\n\n";
    }
  } else {
    markdown += "> 无法获取接口详情\n\n";
  }

  return markdown;
};

// 复制接口MD文档到剪贴板
const copyApiMarkdown = async () => {
  if (!currentApi.value) {
    return;
  }

  try {
    // 使用apiDetail（如果有）或api本身作为detail
    const detail = apiDetail.value || currentApi.value;
    const markdown = generateSingleApiMarkdown(currentApi.value, detail);

    // 使用Clipboard API复制到剪贴板
    if (navigator.clipboard && navigator.clipboard.writeText) {
      await navigator.clipboard.writeText(markdown);
      ElMessage.success("接口文档已复制到剪贴板");
    } else {
      // 降级方案：使用传统方法
      const textArea = document.createElement("textarea");
      textArea.value = markdown;
      textArea.style.position = "fixed";
      textArea.style.left = "-999999px";
      textArea.style.top = "-999999px";
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      try {
        document.execCommand("copy");
        ElMessage.success("接口文档已复制到剪贴板");
      } catch (err) {
        ElMessage.error("复制失败，请手动复制");
      }
      document.body.removeChild(textArea);
    }
  } catch (error) {
    console.error("Failed to copy markdown:", error);
    ElMessage.error("复制失败，请稍后重试");
  }
};

// 导出树数据
const exportTreeData = computed(() => {
  const apiList = exportSearchQuery.value
    ? apis.value.filter((api) => {
        if (!api.action) return false;
        return api.action.toLowerCase().includes(exportSearchQuery.value.toLowerCase());
      })
    : apis.value;
  return buildExportTree(apiList);
});

// 计算总API数量
const totalExportApiCount = computed(() => {
  return apis.value.length;
});

// 过滤树节点
const filterExportNode = (value, data) => {
  if (!value) return true;
  const query = value.toLowerCase();
  if (data.isApi) {
    return data.label.toLowerCase().includes(query);
  }
  // 对于文件夹节点，检查其子节点是否匹配
  return true;
};

// 监听搜索查询，过滤树
watch(exportSearchQuery, (val) => {
  if (exportTreeRef.value) {
    exportTreeRef.value.filter(val);
  }
});

// 处理树节点选择
const handleExportTreeCheck = (data, checked) => {
  const checkedKeys = exportTreeRef.value.getCheckedKeys();
  const halfCheckedKeys = exportTreeRef.value.getHalfCheckedKeys();

  // 收集所有选中的API ID
  const apiIds = new Set();

  const collectApiIds = (nodes) => {
    nodes.forEach((node) => {
      if (node.isApi) {
        if (checkedKeys.includes(node.id) || halfCheckedKeys.includes(node.id)) {
          apiIds.add(node.id);
        }
      } else if (node.children) {
        collectApiIds(node.children);
      }
    });
  };

  // 从树数据中收集所有API ID
  const collectAllApiIds = (nodes) => {
    nodes.forEach((node) => {
      if (node.isApi && checkedKeys.includes(node.id)) {
        apiIds.add(node.id);
      } else if (node.children) {
        collectAllApiIds(node.children);
      }
    });
  };

  collectAllApiIds(exportTreeData.value);
  selectedApiIds.value = Array.from(apiIds);
};

// 全选所有API
const selectAllExportApis = () => {
  if (exportTreeRef.value) {
    // 获取所有API节点
    const getAllApiNodes = (nodes) => {
      const apiNodes = [];
      nodes.forEach((node) => {
        if (node.isApi) {
          apiNodes.push(node.id);
        } else if (node.children) {
          apiNodes.push(...getAllApiNodes(node.children));
        }
      });
      return apiNodes;
    };

    const allApiIds = getAllApiNodes(exportTreeData.value);
    exportTreeRef.value.setCheckedKeys(allApiIds);
    selectedApiIds.value = allApiIds;
  }
};

// 取消全选
const deselectAllExportApis = () => {
  if (exportTreeRef.value) {
    exportTreeRef.value.setCheckedKeys([]);
    selectedApiIds.value = [];
  }
};

// 下载文件辅助函数
const downloadFile = (content, filename, mimeType) => {
  const blob = new Blob([content], { type: mimeType });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  URL.revokeObjectURL(url);
};

// 处理按需导出
const handleExportSelected = async () => {
  if (selectedApiIds.value.length === 0) {
    return;
  }

  downloading.value = true;
  try {
    // 过滤选中的API，直接使用接口列表数据
    const selectedApis = apis.value.filter((api) =>
      selectedApiIds.value.includes(api.uniqueId)
    );

    // 直接使用接口列表数据，不请求详情
    const allApiDetails = selectedApis.map((api) => ({
      api,
      detail: api, // 使用接口列表数据本身作为详情
    }));

    // 导出文档
    const markdown = generateMarkdownDocumentation(allApiDetails);
    const filename = `API文档_${new Date().toISOString().split("T")[0]}.md`;
    downloadFile(markdown, filename, "text/markdown;charset=utf-8");

    ElMessage.success("导出成功！");
  } catch (error) {
    console.error("Failed to export:", error);
    ElMessage.error("导出失败，请稍后重试");
  } finally {
    downloading.value = false;
  }
};
</script>

<style>
* {
  margin: 0;
  padding: 0;
}

/* 移除 scoped，使样式全局生效 */
.type-display a.model-link {
  color: var(--el-color-primary);
  text-decoration: none;
  cursor: pointer;
}

.type-display a.model-link:hover {
  text-decoration: underline;
}

/* 响应式表格样式 */
@media (max-width: 768px) {
  .responsive-table {
    width: 100%;
    overflow-x: auto;
  }

  .responsive-table .el-table__body,
  .responsive-table .el-table__header {
    min-width: 100%;
  }
}
</style>

<style scoped>
.el-container {
  height: 100vh;
}

.mobile-mode {
  flex-direction: column;
}

.mobile-header {
  display: grid;
  grid-template-columns: 40px 1fr 40px;
  align-items: center;
  background-color: #fff;
  border-bottom: 1px solid #eef0f3;
  height: 52px;
  width: 100%;
  padding: 0 8px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
}

.mobile-header h2 {
  margin: 0;
  font-size: 16px;
  font-weight: 600;
  color: #1f2329;
  text-align: center;
}

.menu-toggle-btn {
  font-size: 20px;
  color: #303133;
}

.mobile-header-spacer {
  width: 40px;
}

.mobile-menu-close {
  text-align: right;
  padding: 10px;
  cursor: pointer;
  color: var(--el-color-primary);
}

/* 手机端侧边栏顶部头部（已合并至 sidebar-header） */

.el-aside.sidebar {
  background: #f7f8fa;
  border-right: 1px solid #e4e7ed;
  z-index: 1000;
  overflow: hidden;
}

.sidebar-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.sidebar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 16px 12px;
  flex-shrink: 0;
  border-bottom: 1px solid #eef0f3;
  background: #fff;
}

.sidebar-brand {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.brand-icon {
  font-size: 22px;
  color: var(--el-color-primary);
  flex-shrink: 0;
}

.brand-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.brand-title {
  font-size: 15px;
  font-weight: 600;
  color: #1f2329;
  line-height: 1.3;
}

.brand-subtitle {
  font-size: 12px;
  color: #8f959e;
  margin-top: 2px;
}

.sidebar-close-btn {
  flex-shrink: 0;
  margin-left: 8px;
}

.sidebar-search {
  padding: 10px 12px;
  flex-shrink: 0;
  background: #fff;
  border-bottom: 1px solid #eef0f3;
}

.sidebar-search :deep(.el-input__wrapper) {
  border-radius: 8px;
  box-shadow: 0 0 0 1px #dcdfe6 inset;
  transition: box-shadow 0.2s ease;
}

.sidebar-search :deep(.el-input__wrapper.is-focus) {
  box-shadow: 0 0 0 1px var(--el-color-primary) inset;
}

.sidebar-content {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
  padding-bottom: 16px;
  scrollbar-width: thin;
  scrollbar-color: #dcdfe6 transparent;
}

.sidebar-content::-webkit-scrollbar {
  width: 4px;
}

.sidebar-content::-webkit-scrollbar-thumb {
  background: #dcdfe6;
  border-radius: 4px;
}

.sidebar-content::-webkit-scrollbar-thumb:hover {
  background: #c0c4cc;
}

.sidebar-error {
  padding: 32px 16px;
}

.sidebar-empty {
  padding: 24px 0;
}

@media (max-width: 768px) {
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100vh;
    width: 100%;
    z-index: 2000;
  }
}

.menu-vertical {
  background: transparent;
  border: none;
  padding: 4px 0;
}

.menu-vertical :deep(.el-menu-item) {
  height: 40px;
  line-height: 40px;
  border-radius: 8px;
  margin: 2px 8px;
  padding: 0 10px !important;
  transition: background-color 0.2s ease, color 0.2s ease;
  position: relative;
}

.menu-item-inner {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  min-width: 0;
}

.menu-item-icon {
  font-size: 16px;
  flex-shrink: 0;
}

.menu-item-icon.folder {
  color: #e6a23c;
}

.menu-item-icon.api {
  color: #409eff;
}

.menu-item-label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 13px;
  color: #303133;
}

.menu-item-count {
  flex-shrink: 0;
  font-size: 11px;
  color: #909399;
  background: #eef0f3;
  padding: 1px 6px;
  border-radius: 10px;
  line-height: 16px;
}

.menu-item-arrow {
  flex-shrink: 0;
  font-size: 12px;
  color: #c0c4cc;
  transition: transform 0.2s ease, color 0.2s ease;
}

.menu-folder-item:hover .menu-item-arrow {
  color: var(--el-color-primary);
  transform: translateX(2px);
}

.menu-folder-item :deep(.menu-item-label) {
  font-weight: 500;
}

.menu-vertical :deep(.menu-section-item) {
  height: 32px !important;
  line-height: 32px !important;
  margin-top: 4px !important;
  cursor: default !important;
  opacity: 1 !important;
}

.menu-vertical :deep(.menu-section-item:hover) {
  background: transparent !important;
}

.menu-vertical :deep(.menu-section-item::before) {
  display: none !important;
}

.menu-section-label {
  font-size: 11px;
  font-weight: 600;
  color: #909399;
  letter-spacing: 0.5px;
}

.menu-vertical :deep(.el-menu-item:hover) {
  background-color: #eef2ff;
}

.menu-vertical :deep(.el-menu-item.is-active) {
  background-color: #e8f0fe;
  color: var(--el-color-primary);
}

.menu-vertical :deep(.el-menu-item.is-active)::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 18px;
  background: var(--el-color-primary);
  border-radius: 0 2px 2px 0;
}

.menu-vertical :deep(.menu-api-item.is-active .menu-item-label) {
  color: var(--el-color-primary);
  font-weight: 500;
}

.menu-vertical :deep(.menu-api-item.is-active .menu-item-icon) {
  color: var(--el-color-primary);
}

.main-content {
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0 !important;
  background: #f7f8fa;
}

.content-frame {
  flex: 1;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: #f7f8fa;
}

.content-nav-wrap,
.content-page {
  width: 100%;
  padding-left: 24px;
  padding-right: 24px;
  box-sizing: border-box;
}

.content-nav-wrap {
  flex-shrink: 0;
  padding-top: 16px;
  padding-bottom: 0;
}

.content-nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 20px;
  margin-bottom: 0;
  width: 100%;
  box-sizing: border-box;
}

.content-frame-body {
  flex: 1;
  overflow-y: auto;
}

.content-tab-panel {
  min-height: 100%;
}

.content-nav-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
}

.content-nav-tab {
  border: none;
  background: transparent;
  padding: 6px 14px;
  font-size: 14px;
  font-weight: 500;
  color: #606266;
  border-radius: 6px;
  cursor: pointer;
  transition: background-color 0.2s ease, color 0.2s ease;
  line-height: 1.4;
}

.content-nav-tab:hover {
  color: var(--el-color-primary);
  background: #f0f4ff;
}

.content-nav-tab.active {
  color: var(--el-color-primary);
  background: #ecf5ff;
}

.page-header-card {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.page-header-card-center {
  justify-content: center;
}

.page-header-card-center .page-header-main {
  flex-direction: column;
  align-items: center;
  text-align: center;
}

.page-header-main {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-width: 0;
  flex: 1;
}

.page-header-text {
  min-width: 0;
}

.page-header-label {
  font-size: 12px;
  font-weight: 500;
  color: #909399;
  margin-bottom: 4px;
  letter-spacing: 0.02em;
}

.page-header-card .page-hero-title {
  font-size: 18px;
  margin-bottom: 4px;
}

.page-header-card .page-hero-desc {
  font-size: 13px;
}

.page-header-card-center .page-hero-icon {
  margin-bottom: 8px;
}

.page-header-card-center .page-hero-title {
  font-size: 22px;
}

/* 内容页通用布局 */
.content-page {
  padding-bottom: 24px;
  animation: fadeIn 0.35s ease;
}

.page-hero-icon {
  font-size: 32px;
  color: var(--el-color-primary);
  flex-shrink: 0;
}

.page-hero-title {
  font-size: 18px;
  font-weight: 600;
  color: #1f2329;
  margin: 0 0 4px;
  line-height: 1.4;
}

.page-hero-desc {
  font-size: 13px;
  color: #8f959e;
  margin: 0;
  line-height: 1.6;
}

.content-section {
  background: #fff;
  border: 1px solid #eef0f3;
  border-radius: 10px;
  padding: 20px 24px;
  margin-bottom: 16px;
}

.section-title {
  margin: 0 0 16px;
  padding: 0 0 12px;
  border-bottom: 1px solid #f0f2f5;
  border-left: none;
  background: none;
  border-radius: 0;
  font-size: 15px;
  font-weight: 600;
  color: #1f2329;
  scroll-margin-top: 20px;
  word-break: break-all;
  transition: none;
  transform: none;
}

.section-title:hover {
  background: none;
  transform: none;
}

.model-card {
  margin-bottom: 16px;
}

.model-card:last-child {
  margin-bottom: 0;
}

.model-title {
  margin: 0 0 12px;
  padding: 8px 12px;
  background: #f7f8fa;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  color: #409eff;
  font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace;
  scroll-margin-top: 20px;
  word-break: break-all;
}

.basic-type-display {
  display: inline-block;
  color: #606266;
  margin-bottom: 12px;
  padding: 6px 12px;
  font-size: 13px;
  background: #f7f8fa;
  border-radius: 6px;
  font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace;
}

/* API 详情页 */
.api-detail-icon {
  font-size: 20px;
  color: var(--el-color-primary);
  flex-shrink: 0;
  margin-top: 2px;
}

.api-action-name {
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: #1f2329;
  line-height: 1.5;
  word-break: break-all;
  font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace;
}

.api-detail-alert {
  margin-bottom: 16px;
}

.api-detail-body {
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* README 引导页 */
.readme-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 16px;
  margin-bottom: 16px;
}

.readme-card {
  background: #fff;
  border: 1px solid #eef0f3;
  border-radius: 10px;
  padding: 20px;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}

.readme-card:hover {
  border-color: #d0d7de;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06);
}

.readme-card-num {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  color: var(--el-color-primary);
  background: #ecf5ff;
  padding: 2px 8px;
  border-radius: 4px;
  margin-bottom: 10px;
}

.readme-card h3 {
  margin: 0 0 8px;
  padding: 0;
  border: none;
  background: none;
  font-size: 15px;
  font-weight: 600;
  color: #1f2329;
}

.readme-card p {
  margin: 0 0 10px;
  font-size: 13px;
  color: #8f959e;
  line-height: 1.6;
}

.readme-card ul {
  margin: 0;
  padding-left: 18px;
  font-size: 13px;
  color: #606266;
  line-height: 1.8;
}

.readme-card li {
  margin: 4px 0;
}

.tips-card {
  border-left: 3px solid var(--el-color-primary);
}

.tips-card-title {
  font-size: 14px;
  font-weight: 600;
  color: #1f2329;
  margin-bottom: 12px;
}

.tips-card ul {
  margin: 0;
  padding-left: 20px;
  font-size: 13px;
  color: #606266;
  line-height: 1.8;
}

.tips-card li {
  margin: 6px 0;
}

/* 数据表格 */
.data-table {
  width: 100%;
  border-radius: 8px;
  overflow: hidden;
}

.data-table :deep(.el-table__header th) {
  background: #f7f8fa !important;
  color: #606266;
  font-weight: 600;
  font-size: 13px;
}

.data-table :deep(.el-table__body td) {
  font-size: 13px;
}

.data-table :deep(.el-table__row:hover > td) {
  background: #fafbfc !important;
}

/* 代码示例 */
.code-tabs :deep(.el-tabs__header) {
  margin-bottom: 1px;
  border-radius: 8px 8px 0 0;
  background: #f7f8fa;
  padding: 0 20px;
}

.code-tabs :deep(.el-tabs__item) {
  padding: 0px 10px;
}

.code-tabs :deep(.el-tabs__content) {
  padding: 0;
}

.code-block {
  margin: 0;
  padding: 16px 20px;
  background: #1e1e1e;
  color: #d4d4d4;
  border-radius: 0 0 8px 8px;
  overflow-x: auto;
  font-size: 13px;
  line-height: 1.6;
  font-family: "SF Mono", "Menlo", "Monaco", "Consolas", monospace;
  border: none;
  box-shadow: none;
}

.code-block:hover {
  border: none;
  box-shadow: none;
}

.common-info .content-section:last-child {
  margin-bottom: 0;
}

@keyframes fadeIn {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.el-card {
  margin: 20px 0;
  border-radius: 12px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;
  border: 1px solid #ebeef5;
}

.el-card:hover {
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.12);
  transform: translateY(-2px);
}

h2 {
  margin-bottom: 20px;
}

h3 {
  margin: 20px 0;
  padding: 12px 16px;
  border-left: 4px solid var(--el-color-primary);
  scroll-margin-top: 20px;
  word-break: break-all;
  background: linear-gradient(90deg, #f0f9ff 0%, transparent 100%);
  border-radius: 4px;
  font-weight: 600;
  color: #303133;
}

pre {
  background: linear-gradient(135deg, #f5f7fa 0%, #fafbfc 100%);
  padding: 16px;
  border-radius: 8px;
  overflow-x: auto;
  border: 1px solid #e4e7ed;
  font-size: 13px;
  line-height: 1.6;
}

h4 {
  margin: 15px 0;
  padding: 10px;
  background-color: #f5f7fa;
  scroll-margin-top: 20px;
  word-break: break-all;
}

/* 对象类型的属性名称样式 */
.el-table .object-field {
  color: var(--el-color-primary);
  cursor: pointer;
  text-decoration: underline;
}

/* 内嵌表格样式 */
.el-table__expanded-cell {
  padding: 20px !important;
}

.el-table__expanded-cell .el-table {
  margin-bottom: 0;
}

@media (max-width: 768px) {
  .content-nav-wrap,
  .content-page {
    padding-left: 16px;
    padding-right: 16px;
  }

  .content-page {
    padding-bottom: 16px;
  }

  .content-nav-wrap {
    padding-top: 12px;
  }

  .content-nav-bar {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }

  .content-nav-tabs {
    width: 100%;
  }

  .content-nav-tab {
    flex: 1;
    text-align: center;
  }

  .page-header-card {
    flex-direction: column;
    align-items: stretch;
  }

  .readme-grid {
    grid-template-columns: 1fr;
  }

  .page-header-card-center .page-hero-title {
    font-size: 18px;
  }

  .api-action-name {
    font-size: 13px;
  }

  .content-section {
    padding: 16px;
  }
}

/* 隐藏滚动条但保持可滚动 */
.hide-scrollbar {
  -ms-overflow-style: none;
  /* IE and Edge */
  scrollbar-width: none;
  /* Firefox */
  overflow-y: auto;
}

.hide-scrollbar::-webkit-scrollbar {
  display: none;
  /* Chrome, Safari and Opera */
}

.type-display {
  white-space: nowrap;
}

.type-display a {
  color: var(--el-color-primary);
  text-decoration: none;
  cursor: pointer;
}

.type-display a:hover {
  text-decoration: underline;
}

/* 移动端适配样式 */
@media (max-width: 768px) {
  .el-container {
    height: auto;
    min-height: 100vh;
  }

  .el-main.main-content {
    padding: 0 !important;
    background: #f7f8fa;
  }

  .api-detail {
    max-width: 100%;
  }

  pre {
    font-size: 12px;
  }

  h2 {
    font-size: 1.5rem;
  }

  h3 {
    font-size: 1.2rem;
  }

  h4 {
    font-size: 1rem;
  }
}

/* 移动端字段列表样式 */
.mobile-field-list {
  margin-bottom: 0;
}

.mobile-field-list :deep(.el-collapse) {
  border: 1px solid #eef0f3;
  border-radius: 8px;
  overflow: hidden;
}

.mobile-field-list :deep(.el-collapse-item__header) {
  padding: 0 12px;
  font-size: 13px;
  background: #fafbfc;
}

.mobile-field-list :deep(.el-collapse-item__wrap) {
  border-bottom: none;
}

.mobile-field-title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  width: 100%;
  padding-right: 8px;
}

.field-name {
  font-weight: 600;
  color: #1f2329;
}

.field-required {
  color: #f56c6c;
  background: #fef0f0;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 11px;
}

.mobile-field-content {
  padding: 12px;
  background: #fff;
}

.field-item {
  margin-bottom: 10px;
}

.field-item:last-child {
  margin-bottom: 0;
}

.field-label {
  font-weight: 600;
  margin-bottom: 4px;
  color: #909399;
  font-size: 12px;
}

.field-value {
  padding: 2px 0;
  color: #303133;
  font-size: 13px;
}

/* 目录式导航样式 */
.breadcrumb-nav {
  margin: 8px 8px 4px;
  padding: 10px 12px;
  background: #fff;
  border-radius: 8px;
  border: 1px solid #eef0f3;
}

.breadcrumb-toolbar {
  display: flex;
  gap: 4px;
  margin-bottom: 8px;
  padding-bottom: 8px;
  border-bottom: 1px solid #f0f2f5;
}

.breadcrumb-btn {
  font-size: 13px;
  padding: 4px 8px;
  height: auto;
}

.breadcrumb-path {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 2px;
  font-size: 12px;
  line-height: 1.6;
}

.breadcrumb-tag {
  color: #606266;
  padding: 1px 4px;
  border-radius: 4px;
}

.breadcrumb-clickable {
  cursor: pointer;
  color: var(--el-color-primary);
  transition: background-color 0.2s ease;
}

.breadcrumb-clickable:hover {
  background-color: #ecf5ff;
}

.breadcrumb-current {
  color: #303133;
  font-weight: 500;
}

.breadcrumb-chevron {
  font-size: 10px;
  color: #c0c4cc;
  flex-shrink: 0;
}

/* 导出模块样式 */
.export-drawer :deep(.el-drawer__body) {
  padding: 0;
  overflow-y: auto;
}

.export-module {
  padding: 0 20px 24px;
}

.export-description {
  color: #909399;
  font-size: 13px;
  margin: 0 0 16px;
  line-height: 1.5;
}

.quick-export-card {
  border-radius: 8px;
  margin-bottom: 20px;
  border: 1px solid #eef0f3;
}

.quick-export-card :deep(.el-card__header) {
  padding: 12px 16px;
  background: #fafbfc;
  border-bottom: 1px solid #eef0f3;
}

.quick-export-card :deep(.el-card__body) {
  padding: 16px;
}

.card-header {
  display: flex;
  align-items: center;
  font-weight: 600;
  color: #303133;
}

.quick-export-content {
  text-align: center;
  padding: 10px 0;
}

.quick-export-desc {
  margin-bottom: 20px;
  color: #606266;
  font-size: 14px;
}

/* 按需导出部分 */
.export-section-title {
  margin-bottom: 20px;
  padding-bottom: 15px;
}

.export-section-title h3 {
  margin-bottom: 8px;
  color: #303133;
  font-size: 18px;
}

.section-desc {
  color: #909399;
  font-size: 13px;
  margin: 0;
}

.export-content {
  background: #fafbfc;
  border-radius: 8px;
  padding: 16px;
  border: 1px solid #eef0f3;
}

/* 导出对话框样式 */
.export-dialog-content {
  max-height: 60vh;
  overflow-y: auto;
}

.export-options {
  display: flex;
  gap: 20px;
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid #e4e7ed;
}

.export-select-header {
  margin-bottom: 20px;
  padding-bottom: 15px;
  border-bottom: 1px solid #e4e7ed;
}

.select-actions {
  display: flex;
  align-items: center;
  gap: 15px;
  margin-top: 10px;
}

.selected-count {
  margin-left: auto;
  color: var(--el-color-primary);
  font-weight: 600;
}

.export-api-list {
  max-height: calc(100vh - 420px);
  min-height: 200px;
  overflow-y: auto;
  border: 1px solid #e4e7ed;
  border-radius: 8px;
  padding: 12px;
  margin-bottom: 16px;
  background: #fff;
}

.export-api-item {
  padding: 8px 0;
  border-bottom: 1px solid #f5f7fa;
}

.export-api-item:last-child {
  border-bottom: none;
}

.api-action {
  font-family: "Courier New", monospace;
  color: #606266;
  font-size: 13px;
}

.export-api-item:hover {
  background-color: #f5f7fa;
  border-radius: 4px;
  padding-left: 8px;
  padding-right: 8px;
}

.export-actions {
  text-align: center;
  padding-top: 20px;
  border-top: 1px solid #e4e7ed;
}

/* 导出树样式 */
.export-tree-node {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
}

.api-icon,
.folder-icon {
  font-size: 16px;
}

.node-label {
  flex: 1;
}

.export-api-list :deep(.el-tree-node__content) {
  height: 32px;
  line-height: 32px;
}

.export-api-list :deep(.el-tree-node__label) {
  font-size: 13px;
}

.export-api-list :deep(.el-checkbox) {
  margin-right: 8px;
}

/* 全屏错误状态样式 */
.fullscreen-error {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  width: 100%;
}

/* 禁用 loading 的淡入淡出动画，让初始显示时立即显示 */
:deep(.el-loading-mask) {
  transition: none !important;
}

:deep(.el-loading-mask.is-fullscreen) {
  transition: none !important;
}

:deep(.el-table__inner-wrapper:before) {
  background-color: transparent;
}
:deep(.el-collapse-item__wrap) {
  border-bottom: none;
}
</style>
