<!-- API Key管理 -->
<template>
  <div class="app-container">
    <el-tabs v-model="activeTab" type="card">
      <!-- API Key管理 -->
      <el-tab-pane label="API Key管理" name="management">
        <PageSearch
          ref="searchRef"
          :search-config="searchConfig"
          @query-click="handleQueryClick"
          @reset-click="handleResetClick"
        />

        <PageContent ref="contentRef" :content-config="contentConfig">
          <template #toolbar="{ toolbarRight, onToolbar, removeIds, cols }">
            <CrudToolbarLeft
              :remove-ids="removeIds"
              :perm-create="['module_system:tenant:api-key:create']"
              :perm-delete="['module_system:tenant:api-key:delete']"
              @add="handleOpenDialog('create')"
              @delete="onToolbar('delete')"
            />
            <div class="data-table__toolbar--right">
              <CrudToolbarRight :buttons="toolbarRight" :cols="cols" :on-toolbar="onToolbar" />
            </div>
          </template>

          <template #table="{ data, loading, tableRef, onSelectionChange, pagination }">
            <div class="data-table__content">
              <el-table
                :ref="tableRef as any"
                v-loading="loading"
                row-key="id"
                :data="data"
                height="100%"
                border
                stripe
                @selection-change="onSelectionChange"
              >
                <template #empty>
                  <el-empty :image-size="80" description="暂无数据" />
                </template>
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'selection')?.show"
                  type="selection"
                  min-width="55"
                  align="center"
                />
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'api_key')?.show"
                  key="api_key"
                  label="API Key"
                  prop="api_key"
                  min-width="300"
                  show-overflow-tooltip
                >
                  <template #default="scope">
                    <div class="api-key-container">
                      <span>{{ scope.row.api_key }}</span>
                      <el-button
                        type="text"
                        size="small"
                        @click="copyToClipboard(scope.row.api_key)"
                      >
                        复制
                      </el-button>
                    </div>
                  </template>
                </el-table-column>
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'status')?.show"
                  key="status"
                  label="状态"
                  prop="status"
                  min-width="80"
                  align="center"
                >
                  <template #default="scope">
                    <el-tag :type="scope.row.status === '0' ? 'success' : 'danger'">
                      {{ scope.row.status === "0" ? "正常" : "禁用" }}
                    </el-tag>
                  </template>
                </el-table-column>
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'expired_at')?.show"
                  key="expired_at"
                  label="过期时间"
                  prop="expired_at"
                  min-width="180"
                  show-overflow-tooltip
                />
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'return_url')?.show"
                  key="return_url"
                  label="回调地址"
                  prop="return_url"
                  min-width="200"
                  show-overflow-tooltip
                />
                <!-- <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'last_used_at')?.show"
                  key="last_used_at"
                  label="最后使用时间"
                  prop="last_used_at"
                  min-width="180"
                  show-overflow-tooltip
                >
                  <template #default="scope">
                    {{ scope.row.last_used_at || "未使用" }}
                  </template>
                </el-table-column> -->
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'description')?.show"
                  key="description"
                  label="描述"
                  prop="description"
                  min-width="150"
                  show-overflow-tooltip
                />
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'created_time')?.show"
                  key="created_time"
                  label="创建时间"
                  prop="created_time"
                  min-width="180"
                  show-overflow-tooltip
                />
                <el-table-column
                  v-if="contentCols.find((col) => col.prop === 'operation')?.show"
                  fixed="right"
                  label="操作"
                  align="center"
                  min-width="200"
                >
                  <template #default="scope">
                    <el-button
                      v-hasPerm="['module_system:tenant:api-key:update']"
                      type="primary"
                      size="small"
                      link
                      @click="
                        handleUpdateStatus(scope.row.id, scope.row.status === '0' ? '1' : '0')
                      "
                    >
                      {{ scope.row.status === "0" ? "禁用" : "启用" }}
                    </el-button>
                    <el-button
                      v-hasPerm="['module_system:tenant:api-key:delete']"
                      type="danger"
                      size="small"
                      link
                      @click="handleRowDelete(scope.row.id)"
                    >
                      删除
                    </el-button>
                  </template>
                </el-table-column>
              </el-table>
            </div>
          </template>
        </PageContent>

        <EnhancedDialog
          v-model="dialogVisible.visible"
          :title="dialogVisible.title"
          @close="handleCloseDialog"
          width="500"
        >
          <el-form
            ref="dataFormRef"
            :model="formData"
            :rules="rules"
            label-suffix=":"
            label-width="auto"
            label-position="right"
          >
            <!-- <el-form-item label="租户ID" prop="tenant_id">
              <el-input v-model="formData.tenant_id" placeholder="可选，默认使用当前租户" :maxlength="20" />
            </el-form-item> -->
            <el-form-item label="过期天数" prop="expired_days">
              <el-input
                v-model.number="formData.expired_days"
                type="number"
                placeholder="请输入过期天数"
                min="1"
                :maxlength="4"
              />
            </el-form-item>
            <el-form-item label="描述" prop="description">
              <el-input
                v-model="formData.description"
                type="textarea"
                :rows="3"
                placeholder="请输入描述（可选）"
                :maxlength="255"
              />
            </el-form-item>
            <el-form-item label="回调地址" prop="return_url">
              <el-input
                v-model="formData.return_url"
                type="textarea"
                :rows="2"
                placeholder="请输入回调地址（可选）"
                :maxlength="255"
              />
            </el-form-item>
          </el-form>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="handleCloseDialog">取消</el-button>
              <el-button
                v-hasPerm="['module_system:tenant:api-key:create']"
                type="primary"
                :loading="submitLoading"
                @click="handleSubmit"
              >
                确定
              </el-button>
            </div>
          </template>
        </EnhancedDialog>

        <EnhancedDialog
          v-model="apiKeyDetailVisible"
          title="API Key详情"
          width="600"
          :close-on-press-escape="false"
          :close-on-click-modal="false"
          @close="handleCloseApiKeyDetail"
        >
          <el-alert
            title="请及时保存API Key和Secret，关闭后无法再次查看"
            type="warning"
            :closable="false"
            show-icon
            style="margin-bottom: 16px"
          />
          <el-descriptions :column="1" border>
            <el-descriptions-item label="API Key">
              <div class="api-key-detail">
                <span>{{ apiKeyDetail.api_key }}</span>
                <el-button type="text" size="small" @click="copyToClipboard(apiKeyDetail.api_key)">
                  复制
                </el-button>
              </div>
            </el-descriptions-item>
            <el-descriptions-item label="API Secret">
              <div class="api-key-detail">
                <span>{{ apiKeyDetail.api_secret }}</span>
                <el-button
                  type="text"
                  size="small"
                  @click="copyToClipboard(apiKeyDetail.api_secret || '')"
                >
                  复制
                </el-button>
              </div>
            </el-descriptions-item>
            <el-descriptions-item label="状态">
              <el-tag :type="apiKeyDetail.status === '0' ? 'success' : 'danger'">
                {{ apiKeyDetail.status === "0" ? "正常" : "禁用" }}
              </el-tag>
            </el-descriptions-item>
            <el-descriptions-item label="过期时间">
              {{ apiKeyDetail.expired_at }}
            </el-descriptions-item>
            <el-descriptions-item label="创建时间">
              {{ apiKeyDetail.created_time }}
            </el-descriptions-item>
            <el-descriptions-item label="描述">
              {{ apiKeyDetail.description || "无" }}
            </el-descriptions-item>
            <el-descriptions-item label="回调地址">
              {{ apiKeyDetail.return_url || "无" }}
            </el-descriptions-item>
          </el-descriptions>

          <template #footer>
            <div class="dialog-footer">
              <el-button @click="downloadApiKeyCsv">下载CSV</el-button>
              <el-button type="primary" @click="handleConfirmApiKeyDetail">确认已保存</el-button>
            </div>
          </template>
        </EnhancedDialog>
      </el-tab-pane>

      <!-- 应用配置 -->
      <el-tab-pane label="应用配置" name="config">
        <div class="config-layout">
          <!-- 查询中显示loading -->
          <el-card v-if="configLoading" v-loading="configLoading" class="config-card">
            <template #header>
              <div class="card-header">
                <span>开放平台配置</span>
              </div>
            </template>
          </el-card>

          <!-- 配置不存在时显示创建按钮 -->
          <el-card v-else-if="!configExists" class="config-card">
            <template #header>
              <div class="card-header">
                <span>开放平台配置</span>
              </div>
            </template>
            <div class="config-empty">
              <el-empty description="暂无开放平台配置" />
              <p style="margin: 16px 0; color: #606266">
                请先创建开放平台配置，才能收到平台回调通知。
              </p>
              <el-button type="primary" :loading="configLoading" @click="handleCreateConfig">
                创建配置
              </el-button>
            </div>
          </el-card>

          <!-- 配置存在时显示编辑表单 -->
          <el-card v-else class="config-card">
            <template #header>
              <div class="card-header">
                <span>开放平台配置</span>
              </div>
            </template>
            <el-form
              ref="configFormRef"
              :model="configForm"
              label-width="140px"
              label-position="right"
              style="max-width: 600px"
            >
              <el-form-item label="应用ID">
                <el-input v-model="configForm.app_id" disabled>
                  <template #append>
                    <el-button @click="copyToClipboard(configForm.app_id)">
                      <el-icon><CopyDocument /></el-icon>
                    </el-button>
                  </template>
                </el-input>
              </el-form-item>
              <el-form-item label="网关地址">
                <el-input v-model="configForm.gateway_url" disabled>
                  <template #append>
                    <el-button @click="copyToClipboard(configForm.gateway_url)">
                      <el-icon><CopyDocument /></el-icon>
                    </el-button>
                  </template>
                </el-input>
              </el-form-item>
              <!-- <el-form-item label="异步通知地址">
                <el-input
                  v-model="configForm.notify_url"
                  placeholder="请输入异步通知地址"
                  clearable
                />
              </el-form-item> -->
              <el-form-item label="回调地址">
                <el-input v-model="configForm.return_url" placeholder="请输入回调地址" clearable />
              </el-form-item>
              <el-form-item label="状态">
                <el-tag :type="configForm.status === 'ENABLED' ? 'success' : 'info'">
                  {{ configForm.status === "ENABLED" ? "启用" : "禁用" }}
                </el-tag>
              </el-form-item>
              <!-- <el-form-item label="描述">
                <el-input
                  v-model="configForm.description"
                  type="textarea"
                  :rows="2"
                  disabled
                />
              </el-form-item> -->
              <el-form-item>
                <el-button type="primary" :loading="configLoading" @click="handleSaveConfig">
                  保存配置
                </el-button>
              </el-form-item>
            </el-form>
          </el-card>
        </div>
      </el-tab-pane>

      <!-- 接入文档 -->
      <el-tab-pane label="接入文档" name="docs">
        <div class="docs-layout">
          <!-- 左侧导航 -->
          <div class="docs-sidebar">
            <el-scrollbar>
              <div class="sidebar-section">
                <h3>认证</h3>
                <ul>
                  <li @click="activeSection = 'auth'" :class="{ active: activeSection === 'auth' }">
                    认证方式
                  </li>
                  <li
                    @click="activeSection = 'signature'"
                    :class="{ active: activeSection === 'signature' }"
                  >
                    签名验证
                  </li>
                  <li
                    @click="activeSection = 'notes'"
                    :class="{ active: activeSection === 'notes' }"
                  >
                    注意事项
                  </li>
                </ul>
              </div>
              <div class="sidebar-section">
                <h3>账户接口</h3>
                <ul>
                  <li
                    @click="activeSection = 'transfer'"
                    :class="{ active: activeSection === 'transfer' }"
                  >
                    发起转账
                  </li>
                  <li
                    @click="activeSection = 'transfer_query'"
                    :class="{ active: activeSection === 'transfer_query' }"
                  >
                    查询转账
                  </li>
                  <li
                    @click="activeSection = 'balance'"
                    :class="{ active: activeSection === 'balance' }"
                  >
                    账户余额
                  </li>
                </ul>
              </div>
              <div class="sidebar-section">
                <h3>回调通知</h3>
                <ul>
                  <li
                    @click="activeSection = 'callback'"
                    :class="{ active: activeSection === 'callback' }"
                  >
                    通知接口
                  </li>
                </ul>
              </div>
              <div class="sidebar-section">
                <h3>其他</h3>
                <ul>
                  <li
                    @click="activeSection = 'errors'"
                    :class="{ active: activeSection === 'errors' }"
                  >
                    常见错误
                  </li>
                  <li @click="activeSection = 'php'" :class="{ active: activeSection === 'php' }">
                    PHP示例代码
                  </li>
                </ul>
                identity_type
              </div>
            </el-scrollbar>
          </div>

          <!-- 右侧内容 -->
          <div class="docs-content">
            <el-card>
              <template #header>
                <div class="card-header">
                  <span>{{ getSectionTitle() }}</span>
                </div>
              </template>

              <div v-if="activeSection === 'auth'" class="section-content">
                <h2>1. 认证方式</h2>
                <p>使用API Key进行认证时，需要在请求头中添加以下信息：</p>
                <pre><code>Authorization: ApiKey {api_key}
Signature: {signature}</code></pre>
                <p>其中：</p>
                <ul>
                  <li>
                    <strong>Authorization</strong>
                    ：API Key认证头，格式为
                    <code>ApiKey {api_key}</code>
                  </li>
                  <li>
                    <strong>Signature</strong>
                    ：请求签名（必填），用于验证请求数据的完整性
                  </li>
                </ul>
              </div>

              <div v-else-if="activeSection === 'signature'" class="section-content">
                <h2>2. 签名验证</h2>
                <p>签名用于验证请求数据的完整性，防止数据被篡改。签名生成步骤：</p>
                <ol>
                  <li>
                    过滤请求参数：排除
                    <code>sign</code>
                    参数、
                    <code>null</code>
                    值、空字符串、空数组、空对象
                  </li>
                  <li>将过滤后的参数按参数名ASCII码升序排序</li>
                  <li>
                    对字典或列表类型的值进行JSON序列化（
                    <code>sort_keys=true</code>
                    ，
                    <code>separators=(',', ':')</code>
                    ）
                  </li>
                  <li>
                    对每个参数值进行URL编码（
                    <code>UTF-8</code>
                    编码）
                  </li>
                  <li>
                    将排序后的参数拼接为字符串：
                    <code>key1=value1&amp;key2=value2</code>
                  </li>
                  <li>使用API Secret作为密钥，通过HMAC-SHA256算法生成签名</li>
                  <li>
                    将签名添加到请求头
                    <code>Signature</code>
                    中
                  </li>
                </ol>
                <h3>2.1 签名计算示例</h3>
                <pre><code># 原始请求数据
{
  "account_book_id": "123456",
  "amount": "100.00",
  "payee_info": {
    "identity_type": "ALIPAY_ACCOUNT",
    "name": "张三",
    "identity": "zhangsan@example.com"
  },
  "sign": "不需要参与签名",
  "empty_param": "",
  "null_param": null
}

# 1. 过滤后（排除sign、空字符串、null）
{
  "account_book_id": "123456",
  "amount": "100.00",
  "payee_info": {
    "identity_type": "ALIPAY_ACCOUNT",
    "name": "张三",
    "identity": "zhangsan@example.com"
  }
}

# 2. 按参数名升序排序
account_book_id, amount, payee_info

# 3. JSON序列化嵌套对象
payee_info={"identity":"zhangsan@example.com","identity_type":"ALIPAY_ACCOUNT","name":"张三"}

# 4. URL编码（处理中文）
name=%E5%BC%A0%E4%B8%89

# 5. 拼接字符串
account_book_id=123456&amount=100.0&payee_info=%7B%22identity%22%3A%22zhangsan%40example.com%22%2C%22identity_type%22%3A%22ALIPAY_ACCOUNT%22%2C%22name%22%3A%22%E5%BC%A0%E4%B8%89%22%7D

# 6. HMAC-SHA256签名（密钥为API Secret）
signature = HMAC-SHA256(api_secret, sign_str)

# 7. 请求头中添加签名
Signature: {signature}</code></pre>
              </div>

              <div v-else-if="activeSection === 'notes'" class="section-content">
                <h2>3. 注意事项</h2>
                <ul>
                  <li>API Key和Secret请妥善保管，不要泄露给他人</li>
                  <li>
                    签名验证是
                    <strong>必填</strong>
                    的，未带签名或签名错误将返回401
                  </li>
                  <li>签名使用HMAC-SHA256算法，密钥为API Secret</li>
                  <li>
                    签名计算前会自动过滤：
                    <code>sign</code>
                    参数、
                    <code>null</code>
                    值、空字符串、空数组、空对象
                  </li>
                  <li>
                    嵌套对象（如
                    <code>payee_info</code>
                    ）会先进行JSON序列化再参与签名
                  </li>
                  <li>参数值会进行URL编码（UTF-8），确保中文字符正确处理</li>
                  <li>定期更新API Key，建议每3-6个月更换一次</li>
                  <li>如发现API Key泄露，请立即禁用并重新生成</li>
                  <li>API Key有过期时间，请在过期前及时更新</li>
                </ul>
              </div>

              <div v-else-if="activeSection === 'transfer'" class="section-content">
                <h2>4. 发起转账</h2>
                <h3>4.1 接口说明</h3>
                <p>从资金账户转账到支付宝账户/银行卡</p>

                <h4>API接口地址</h4>
                <p><code>POST https://api.qcsj88888.com/payment/openapi/account/transfer</code></p>

                <h4>请求参数</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>参数名</th>
                      <th>类型</th>
                      <th>是否必填</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>account_book_id</td>
                      <td>string</td>
                      <td>是</td>
                      <td>付款方资金账户号</td>
                    </tr>
                    <tr>
                      <td>amount</td>
                      <td>string</td>
                      <td>是</td>
                      <td>转账金额，单位为元，精确到小数点后两位，大于0.02元</td>
                    </tr>
                    <tr>
                      <td>order_title</td>
                      <td>string</td>
                      <td>否</td>
                      <td>转账标题</td>
                    </tr>
                    <tr>
                      <td>remark</td>
                      <td>string</td>
                      <td>否</td>
                      <td>转账备注</td>
                    </tr>
                    <tr>
                      <td>third_biz_no</td>
                      <td>string</td>
                      <td>是</td>
                      <td>三方订单号（商户侧唯一标识，不可重复）</td>
                    </tr>
                    <tr>
                      <td>payee_info</td>
                      <td>object</td>
                      <td>是</td>
                      <td>
                        <div class="expandable-section">
                          <span @click="toggleExpand('payee_info')" class="expand-btn">
                            {{ expandedSections.payee_info ? "▼" : "▶" }} 收款方信息
                          </span>
                          <div v-if="expandedSections.payee_info" class="expandable-content">
                            <table class="api-table nested-table">
                              <thead>
                                <tr>
                                  <th>参数名</th>
                                  <th>类型</th>
                                  <th>是否必填</th>
                                  <th>描述</th>
                                </tr>
                              </thead>
                              <tbody>
                                <tr>
                                  <td>identity_type</td>
                                  <td>string</td>
                                  <td>是</td>
                                  <td>收款方类型：alipay（支付宝账户）/ bank（银行卡）</td>
                                </tr>
                                <tr>
                                  <td>name</td>
                                  <td>string</td>
                                  <td>是</td>
                                  <td>收款方真实姓名</td>
                                </tr>
                                <tr>
                                  <td>identity</td>
                                  <td>string</td>
                                  <td>是</td>
                                  <td>收款方唯一标识（支付宝账号/银行卡号）</td>
                                </tr>
                                <tr>
                                  <td>bankcard_ext_info</td>
                                  <td>object</td>
                                  <td>否</td>
                                  <td>
                                    <div class="expandable-section">
                                      <span
                                        @click="toggleExpand('bankcard_ext_info')"
                                        class="expand-btn"
                                      >
                                        {{ expandedSections.bankcard_ext_info ? "▼" : "▶" }}
                                        银行卡信息（当 identity_type 为 bank 时必填）
                                      </span>
                                      <div
                                        v-if="expandedSections.bankcard_ext_info"
                                        class="expandable-content"
                                      >
                                        <table class="api-table nested-table">
                                          <thead>
                                            <tr>
                                              <th>参数名</th>
                                              <th>类型</th>
                                              <th>是否必填</th>
                                              <th>描述</th>
                                            </tr>
                                          </thead>
                                          <tbody>
                                            <tr>
                                              <td>account_type</td>
                                              <td>string</td>
                                              <td>是</td>
                                              <td>收款账户类型: 1/2。对公: 1，对私: 2</td>
                                            </tr>
                                            <tr>
                                              <td>inst_name</td>
                                              <td>string</td>
                                              <td>否</td>
                                              <td>机构名称（当 account_type 是 1 时必填）</td>
                                            </tr>
                                            <tr>
                                              <td>inst_province</td>
                                              <td>string</td>
                                              <td>否</td>
                                              <td>银行所在省份</td>
                                            </tr>
                                            <tr>
                                              <td>inst_city</td>
                                              <td>string</td>
                                              <td>否</td>
                                              <td>收款银行所在市</td>
                                            </tr>
                                            <tr>
                                              <td>inst_branch_name</td>
                                              <td>string</td>
                                              <td>否</td>
                                              <td>收款银行所属支行</td>
                                            </tr>
                                            <tr>
                                              <td>bank_code</td>
                                              <td>string</td>
                                              <td>否</td>
                                              <td>银行支行联行号</td>
                                            </tr>
                                          </tbody>
                                        </table>
                                      </div>
                                    </div>
                                  </td>
                                </tr>
                              </tbody>
                            </table>
                          </div>
                        </div>
                      </td>
                    </tr>
                  </tbody>
                </table>

                <h4>请求示例</h4>
                <pre><code>curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/transfer' \
  -H 'Authorization: ApiKey your_api_key' \
  -H 'Signature: your_signature' \
  -H 'Content-Type: application/json' \
  -d '{
    "account_book_id": "资金账号",
    "amount": "100.00",
    "order_title": "转账标题",
    "third_biz_no": "商户订单号202604270001",
    "payee_info": {
      "identity_type": "ALIPAY_ACCOUNT",
      "name": "收款人姓名",
      "identity": "收款人支付宝账号"
    }
  }'</code></pre>

                <h4>响应示例</h4>
                <pre><code>{"code": 200, "message": "转账申请已提交", "data": {"status": "DEALING", "order_no": "2026042711122334455", "third_biz_no": "商户订单号202604270001"}}</code></pre>
              </div>

              <div v-else-if="activeSection === 'transfer_query'" class="section-content">
                <h2>5. 查询转账</h2>
                <h3>5.1 接口说明</h3>
                <p>根据三方订单号查询转账状态和详情</p>

                <h4>API接口地址</h4>
                <p>
                  <code>POST https://api.qcsj88888.com/payment/openapi/account/transfer/query</code>
                </p>

                <h4>请求参数</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>参数名</th>
                      <th>类型</th>
                      <th>是否必填</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>third_biz_no</td>
                      <td>string</td>
                      <td>是</td>
                      <td>三方订单号（发起转账时传入的商户侧唯一标识）</td>
                    </tr>
                  </tbody>
                </table>

                <h4>请求示例</h4>
                <pre><code>curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/transfer/query' \
  -H 'Authorization: ApiKey your_api_key' \
  -H 'Signature: your_signature' \
  -H 'Content-Type: application/json' \
  -d '{
    "third_biz_no": "商户订单号202604270001"
  }'</code></pre>

                <h4>响应示例</h4>
                <pre><code>{
  "code": 200,
  "message": "查询成功",
  "data": {
    "status": "SUCCESS",
    "order_no": "2026042711122334455",
    "amount": "100.00",
    "payee_info": {
      "identity_type": "ALIPAY_ACCOUNT",
      "name": "张*",
      "identity": "z****@example.com"
    },
    "created_time": "2026-04-27 11:22:33",
    "updated_time": "2026-04-27 11:25:45"
  }
}</code></pre>

                <h4>状态说明</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>状态码</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>DEALING</td>
                      <td>处理中</td>
                    </tr>
                    <tr>
                      <td>SUCCESS</td>
                      <td>成功</td>
                    </tr>
                    <tr>
                      <td>FAIL</td>
                      <td>失败</td>
                    </tr>
                    <tr>
                      <td>REFUND</td>
                      <td>已退款</td>
                    </tr>
                  </tbody>
                </table>
              </div>

              <div v-else-if="activeSection === 'balance'" class="section-content">
                <h2>6. 账户余额</h2>
                <h3>6.1 接口说明</h3>
                <p>查询指定企业资金专户的余额信息</p>

                <h4>API接口地址</h4>
                <p>
                  <code>POST https://api.qcsj88888.com/payment/openapi/account/balance/query</code>
                </p>

                <h4>请求参数</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>参数名</th>
                      <th>类型</th>
                      <th>是否必填</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>enterprise_id</td>
                      <td>string</td>
                      <td>是</td>
                      <td>企业ID</td>
                    </tr>
                  </tbody>
                </table>

                <h4>请求示例</h4>
                <pre><code>curl -X POST 'https://api.qcsj88888.com/payment/openapi/account/balance/query' \
  -H 'Authorization: ApiKey your_api_key' \
  -H 'Signature: your_signature' \
  -H 'Content-Type: application/json' \
  -d '{
    "enterprise_id": "2088480777900000"
  }'</code></pre>

                <h4>响应示例</h4>
                <pre><code>{
  "code": 200,
  "message": "查询成功",
  "data": [
    {
      "account_book_id": "2088480770900000",
      "available_amount": "50000.00",
      "enable_status": "ENABLE",
      "scene": "B2B_TRANS",
      "account_card_info": {
        "card_no": "xxxx",
        "bank_name": "招商银行"
      }
    }
  ]
}</code></pre>

                <h4>响应字段说明</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>字段名</th>
                      <th>类型</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>account_book_id</td>
                      <td>string</td>
                      <td>资金专户号</td>
                    </tr>
                    <tr>
                      <td>available_amount</td>
                      <td>string</td>
                      <td>可用余额（单位：元，精确到小数点后两位）</td>
                    </tr>
                    <tr>
                      <td>enable_status</td>
                      <td>string</td>
                      <td>启用状态：ENABLE（启用）/ DISABLE（禁用）</td>
                    </tr>
                    <tr>
                      <td>scene</td>
                      <td>string</td>
                      <td>场景类型：B2B_TRANS（B2B转账）</td>
                    </tr>
                    <tr>
                      <td>account_card_info</td>
                      <td>object</td>
                      <td>账户卡信息（银行卡号、银行名称等）</td>
                    </tr>
                  </tbody>
                </table>

                <h4>注意事项</h4>
                <ul>
                  <li>
                    返回结果为
                    <strong>数组</strong>
                    ，一个企业可能有多个资金专户
                  </li>
                  <li>
                    余额单位为
                    <strong>元</strong>
                    ，精确到小数点后两位
                  </li>
                  <li>
                    仅返回
                    <code>scene</code>
                    为
                    <code>B2B_TRANS</code>
                    的资金专户
                  </li>
                </ul>
              </div>

              <div v-else-if="activeSection === 'callback'" class="section-content">
                <h2>7. 回调通知</h2>
                <h3>7.1 接口说明</h3>
                <p>当转账状态发生变化时，系统会主动向商户配置的回调地址发送通知。</p>

                <h4>回调地址配置</h4>
                <p>系统按照以下优先级获取回调地址：</p>
                <ol style="margin-left: 20px">
                  <li>
                    <strong>API Key 级别</strong>
                    ：在创建/编辑 API Key 时配置回调地址（优先级最高）
                  </li>
                  <li>
                    <strong>开放平台配置</strong>
                    ：在
                    <strong>应用配置</strong>
                    页面设置默认回调地址
                  </li>
                </ol>
                <p style="color: #909399; margin-top: 8px">
                  说明：如果 API Key 已配置回调地址，则优先使用；否则使用开放平台配置中的回调地址。
                </p>

                <h4>通知方式</h4>
                <ul>
                  <li>
                    <strong>POST 请求</strong>
                    ：系统通过 HTTP POST 方式将通知数据发送到商户的回调地址
                  </li>
                  <li>
                    <strong>表单形式</strong>
                    ：通知参数以表单形式提交（Content-Type: multipart/form-data）
                  </li>
                  <li>
                    <strong>重试机制</strong>
                    ：如果通知失败，系统会自动重试（最多2次，间隔1秒、2秒）
                  </li>
                </ul>

                <h4>请求参数</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>参数名</th>
                      <th>类型</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>notify_id</td>
                      <td>string</td>
                      <td>通知ID，唯一标识</td>
                    </tr>
                    <tr>
                      <td>timestamp</td>
                      <td>int</td>
                      <td>通知时间戳（毫秒）</td>
                    </tr>
                    <tr>
                      <td>content</td>
                      <td>string</td>
                      <td>JSON格式的通知内容</td>
                    </tr>
                  </tbody>
                </table>

                <h4>content 字段说明</h4>
                <table class="api-table">
                  <thead>
                    <tr>
                      <th>参数名</th>
                      <th>类型</th>
                      <th>描述</th>
                    </tr>
                  </thead>
                  <tbody>
                    <tr>
                      <td>status</td>
                      <td>string</td>
                      <td>转账状态：SUCCESS（成功）、FAIL（失败）</td>
                    </tr>
                    <tr>
                      <td>order_no</td>
                      <td>string</td>
                      <td>平台订单号</td>
                    </tr>
                    <tr>
                      <td>third_biz_no</td>
                      <td>string</td>
                      <td>商户订单号（发起转账时传入的三方订单号）</td>
                    </tr>
                    <tr>
                      <td>amount</td>
                      <td>number</td>
                      <td>转账金额（元）</td>
                    </tr>
                    <tr>
                      <td>created_time</td>
                      <td>string</td>
                      <td>创建时间</td>
                    </tr>
                    <tr>
                      <td>updated_time</td>
                      <td>string</td>
                      <td>更新时间</td>
                    </tr>
                  </tbody>
                </table>

                <h4>通知示例</h4>
                成功示例
                <pre v-pre><code>POST /your/callback/url HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"

n1234567890123456789
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"

1715767200000
------WebKitFormBoundary
Content-Disposition: form-data; name="content"

{
  "status": "SUCCESS",
  "order_no": "2026042711122334455",
  "third_biz_no": "商户订单号202604270001",
  "amount": "100.00",
  "created_time": "2026-04-27 11:22:33",
  "updated_time": "2026-04-27 11:25:45"
}

------WebKitFormBoundary--
                转账成功示例
POST /商户回调地址 HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"

n12535554089713704963
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"

1779037365774
------WebKitFormBoundary
Content-Disposition: form-data; name="content"

{
  "status": "SUCCESS",
  "order_no": "2026042711122334455",
  "third_biz_no": "商户订单号202604270001",
  "amount": "100.00",
  "out_biz_no": "12535474352010076162",
  "enterprise_id": "2088480767913636",
  "account_book_id": "2088480770941200",
  "order_title": "转账标题",
  "created_time": "2026-04-27 11:22:33"
}
------WebKitFormBoundary--

                转账失败示例
POST /your/callback/url HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary

------WebKitFormBoundary
Content-Disposition: form-data; name="notify_id"

n12535554089713704963
------WebKitFormBoundary
Content-Disposition: form-data; name="timestamp"

1779037365774
------WebKitFormBoundary
Content-Disposition: form-data; name="content"

{
  "status": "FAIL",
  "third_biz_no": "商户订单号202604270001",
  "amount": "1.00",
  "error_msg": "收款账号不存在或姓名有误，建议核实账号和姓名是否准确"
}
------WebKitFormBoundary--
------WebKitFormBoundary--
</code></pre>

                <h4>响应要求</h4>
                <p>
                  商户服务端收到通知后，需要返回 HTTP 200 状态码表示成功接收。如果返回非 200
                  状态码或超时，系统会进行重试。
                </p>

                <h4>注意事项</h4>
                <ul>
                  <li>
                    回调地址需要支持
                    <strong>HTTPS</strong>
                    协议
                  </li>
                  <li>
                    确保回调接口能够在
                    <strong>5秒内</strong>
                    返回响应
                  </li>
                  <li>
                    <span style="color: #f56c6c">
                      <strong>重要</strong>
                      ：回调通知不包含签名验证，收到通知后请主动调用查询接口确认订单状态，以确保数据真实性
                    </span>
                  </li>
                  <li>
                    通知可能会重复发送，请确保业务逻辑支持
                    <strong>幂等性</strong>
                  </li>
                  <li>
                    系统最多重试
                    <strong>2次</strong>
                    ，重试间隔为 1 秒和 2 秒
                  </li>
                </ul>
              </div>

              <div v-else-if="activeSection === 'errors'" class="section-content">
                <h2>8. 常见错误</h2>
                <ul>
                  <li>
                    <strong>401 Invalid API Key</strong>
                    ：API Key无效或已过期
                  </li>
                  <li>
                    <strong>401 Signature header required</strong>
                    ：未提供Signature请求头
                  </li>
                  <li>
                    <strong>401 Invalid Signature</strong>
                    ：签名验证失败，请检查签名计算方式
                  </li>
                  <li>
                    <strong>400 Bad Request</strong>
                    ：请求参数错误
                  </li>
                  <li>
                    <strong>403 Forbidden</strong>
                    ：无权限访问
                  </li>
                  <li>
                    <strong>500 Internal Server Error</strong>
                    ：服务器内部错误
                  </li>
                </ul>
              </div>

              <div v-else-if="activeSection === 'php'" class="section-content">
                <h2>9. PHP 示例代码</h2>
                <h3>9.1 以下是签名生成的 PHP 示例代码：</h3>
                <pre class="code-block"><code class="language-php">&lt;?php

class SignatureGenerator
{
    private static function ksortRecursive(&$array) {
        if (!is_array($array)) return;
        ksort($array, SORT_STRING);
        foreach ($array as &$value) {
            self::ksortRecursive($value);
        }
    }

    public static function generateSignature(
        string $apiSecret,
        array $requestData,
        array $excludeParams = ['sign']
    ): string {
        $filteredData = [];
        foreach ($requestData as $key => $value) {
            if (in_array($key, $excludeParams, true)) {
                continue;
            }
            if ($value === null || $value === '') {
                continue;
            }
            if (is_array($value) && empty($value)) {
                continue;
            }
            $filteredData[$key] = $value;
        }

        self::ksortRecursive($filteredData);

        $collect = [];
        foreach ($filteredData as $key => $value) {
            if (is_array($value)) {
                $value = json_encode($value, JSON_UNESCAPED_SLASHES);
            }
            $encodedValue = rawurlencode((string)$value);
            $collect[] = "{$key}={$encodedValue}";
        }

        $signStr = implode('&', $collect);
        return hash_hmac('sha256', $signStr, $apiSecret);
    }

    public static function verifySignature(
        string $apiSecret,
        array $requestData,
        string $signature
    ): bool {
        $expectedSignature = self::generateSignature($apiSecret, $requestData);
        return hash_equals($expectedSignature, $signature);
    }
}

// ================= 测试调用 =================

$apiSecret = 'your_api_secret_here';
$requestData = [
    "account_book_id" => "2088480770900000",
    "amount" => "1.00",
    "order_title" => "Apikey转账",
    "third_biz_no" => "1234242026042700111",
    "payee_info" => [
        "identity_type" => "ALIPAY_ACCOUNT",
        "name" => "钱先生",
        "identity" => "1xx9xx9xxxxx"
    ]
];

// 生成签名
$signature = SignatureGenerator::generateSignature($apiSecret, $requestData);
echo "生成的签名: {$signature}\n";

// 验证签名
$isValid = SignatureGenerator::verifySignature($apiSecret, $requestData, $signature);
echo "签名验证结果: " . ($isValid ? '有效' : '无效') . "\n";
?&gt;</code></pre>
              </div>
            </el-card>
          </div>
        </div>
      </el-tab-pane>
    </el-tabs>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import ApiKeyAPI, {
  ApiKeyCreateForm,
  ApiKeyPageQuery,
  ApiKeyResponse,
} from "@/api/module_payment/apikey";
import OpenAPI from "@/api/module_payment/openapi";
import CrudToolbarLeft from "@/components/CURD/CrudToolbarLeft.vue";
import CrudToolbarRight from "@/components/CURD/CrudToolbarRight.vue";
import PageSearch from "@/components/CURD/PageSearch.vue";
import PageContent from "@/components/CURD/PageContent.vue";
import EnhancedDialog from "@/components/CURD/EnhancedDialog.vue";
import { useCrudList } from "@/components/CURD/useCrudList";
import type { IContentConfig, ISearchConfig } from "@/components/CURD/types";
import { ElMessage } from "element-plus";
import { Loading, CopyDocument } from "@element-plus/icons-vue";
import { watch } from "vue";

defineOptions({
  name: "ApiKey",
  inheritAttrs: false,
});

const activeTab = ref("management");
const activeSection = ref("auth");
const { searchRef, contentRef, handleQueryClick, handleResetClick, refreshList } = useCrudList();
const dataFormRef = ref();
const submitLoading = ref(false);
const apiKeyDetailVisible = ref(false);
const configFormRef = ref();
const configLoading = ref(true);
const expandedSections = ref({
  payee_info: false,
  bankcard_ext_info: false,
});

const configExists = ref(false);

const configForm = reactive({
  app_id: "",
  gateway_url: "",
  notify_url: "",
  return_url: "",
  status: "ENABLED",
  description: "",
});

watch(activeTab, (newTab) => {
  if (newTab === "config") {
    loadOpenConf();
  }
});

async function loadOpenConf() {
  configLoading.value = true;
  configExists.value = false;
  try {
    const res = await OpenAPI.getOpenConf();
    if (res.data.code === 0 && res.data.data) {
      Object.assign(configForm, res.data.data);
      configExists.value = true;
    } else {
      configExists.value = false;
    }
  } catch (error: any) {
    console.error("加载配置失败:", error);
    // 如果返回"配置不存在"错误，则显示创建按钮
    if (error?.response?.data?.msg?.includes("配置不存在")) {
      configExists.value = false;
    }
  } finally {
    configLoading.value = false;
  }
}

async function handleCreateConfig() {
  configLoading.value = true;
  try {
    const res = await OpenAPI.saveOpenConf({
      notify_url: "",
      return_url: "",
    });
    if (res.data.code === 0 && res.data.data) {
      Object.assign(configForm, res.data.data);
      configExists.value = true;
      ElMessage.success("创建成功");
    }
  } catch (error) {
    console.error(error);
    ElMessage.error("创建失败");
  } finally {
    configLoading.value = false;
  }
}

async function handleSaveConfig() {
  configLoading.value = true;
  try {
    const res = await OpenAPI.saveOpenConf({
      notify_url: configForm.notify_url,
      return_url: configForm.return_url,
    });
    if (res.data.code === 0 && res.data.data) {
      Object.assign(configForm, res.data.data);
    }
  } catch (error) {
    console.error(error);
  } finally {
    configLoading.value = false;
  }
}

function toggleExpand(section: string) {
  expandedSections.value[section] = !expandedSections.value[section];
}

function getSectionTitle() {
  const titles = {
    auth: "认证方式",
    signature: "签名验证",
    notes: "注意事项",
    transfer: "发起转账",
    transfer_query: "查询转账",
    balance: "账户余额",
    callback: "回调通知",
    errors: "常见错误",
    php: "PHP示例代码",
  };
  return titles[activeSection.value] || "API文档";
}

const apiKeyDetail = reactive<ApiKeyResponse>({
  id: 0,
  api_key: "",
  api_secret: "",
  status: "0",
  expired_at: "",
  created_time: "",
  return_url: "",
});

const searchConfig = reactive<ISearchConfig>({
  permPrefix: "module_system:tenant:api-key",
  colon: true,
  isExpandable: true,
  showNumber: 2,
  form: { labelWidth: "auto" },
  formItems: [
    {
      prop: "status",
      label: "状态",
      type: "select",
      attrs: {
        placeholder: "请选择状态",
        clearable: true,
        options: [
          { label: "正常", value: "0" },
          { label: "禁用", value: "1" },
        ],
        style: { width: "167.5px" },
      },
    },
  ],
});

const contentCols = reactive<
  Array<{
    prop?: string;
    label?: string;
    show?: boolean;
  }>
>([
  { prop: "selection", label: "选择框", show: true },
  { prop: "id", label: "ID", show: false },
  { prop: "api_key", label: "API Key", show: true },
  { prop: "status", label: "状态", show: true },
  { prop: "return_url", label: "回调地址", show: true },
  { prop: "expired_at", label: "过期时间", show: true },
  { prop: "last_used_at", label: "最后使用时间", show: true },
  { prop: "description", label: "描述", show: true },
  { prop: "created_time", label: "创建时间", show: true },
  { prop: "operation", label: "操作", show: true },
]);

const contentConfig = reactive<IContentConfig<ApiKeyPageQuery>>({
  permPrefix: "module_system:tenant:api-key",
  pk: "id",
  cols: contentCols as IContentConfig["cols"],
  hideColumnFilter: false,
  toolbar: [],
  defaultToolbar: [{ name: "refresh", perm: "refresh" }, "filter"],
  pagination: {
    pageSize: 10,
    pageSizes: [10, 20, 30, 50],
  },
  request: { page_no: "page", page_size: "page_size" },
  indexAction: async (params) => {
    const res = await ApiKeyAPI.listApiKey(params as ApiKeyPageQuery);
    return {
      total: res.data.data.total,
      list: res.data.data.items,
    };
  },
  deleteAction: async (ids) => {
    const idList = ids
      .split(",")
      .map((s) => Number(s.trim()))
      .filter((n) => !Number.isNaN(n));
    for (const id of idList) {
      await ApiKeyAPI.deleteApiKey(id);
    }
  },
  deleteConfirm: {
    title: "警告",
    message: "确认删除该项数据?",
    type: "warning",
  },
});

const formData = reactive<ApiKeyCreateForm>({
  tenant_id: undefined,
  expired_days: 365,
  description: "",
  return_url: "",
});

const dialogVisible = reactive({
  title: "",
  visible: false,
  type: "create" as "create",
});

const rules = reactive({
  expired_days: [{ required: true, message: "请输入过期天数", trigger: "blur" }],
});

const initialFormData: ApiKeyCreateForm = {
  tenant_id: undefined,
  expired_days: 365,
  description: "",
};

async function handleRowDelete(id: number) {
  contentRef.value?.handleDelete(id);
}

async function resetForm() {
  if (dataFormRef.value) {
    dataFormRef.value.resetFields();
    dataFormRef.value.clearValidate();
  }
  Object.assign(formData, initialFormData);
}

async function handleCloseDialog() {
  dialogVisible.visible = false;
  await resetForm();
}

async function handleOpenDialog(type: "create") {
  dialogVisible.type = type;
  dialogVisible.title = "创建API Key";
  dialogVisible.visible = true;
}

async function handleSubmit() {
  dataFormRef.value.validate(async (valid: boolean) => {
    if (valid) {
      submitLoading.value = true;
      try {
        const response = await ApiKeyAPI.createApiKey(formData);
        Object.assign(apiKeyDetail, response.data.data);
        apiKeyDetailVisible.value = true;
        dialogVisible.visible = false;
        await resetForm();
        refreshList();
      } catch (error: unknown) {
        console.error(error);
      } finally {
        submitLoading.value = false;
      }
    }
  });
}

async function handleUpdateStatus(id: number, status: string) {
  try {
    await ApiKeyAPI.updateApiKeyStatus(id, { status });
    ElMessage.success(`API Key已${status === "0" ? "启用" : "禁用"}`);
    refreshList();
  } catch (error: unknown) {
    console.error(error);
    ElMessage.error("操作失败");
  }
}

function copyToClipboard(text: string) {
  navigator.clipboard
    .writeText(text)
    .then(() => {
      ElMessage.success("复制成功");
    })
    .catch(() => {
      ElMessage.error("复制失败");
    });
}

function handleCloseApiKeyDetail() {
  ElMessage.warning("请务必已保存API Key和Secret，关闭后将无法再次查看");
  apiKeyDetailVisible.value = false;
}

function handleConfirmApiKeyDetail() {
  ElMessage.success("已确认保存");
  apiKeyDetailVisible.value = false;
}

function downloadApiKeyCsv() {
  const csvContent = `API Key,API Secret,状态,过期时间,创建时间,描述\n"${apiKeyDetail.api_key}","${apiKeyDetail.api_secret}","${apiKeyDetail.status === "0" ? "正常" : "禁用"}","${apiKeyDetail.expired_at}","${apiKeyDetail.created_time}","${apiKeyDetail.description || ""}"`;
  const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
  const link = document.createElement("a");
  const url = URL.createObjectURL(blob);
  link.setAttribute("href", url);
  link.setAttribute("download", `api-key-${apiKeyDetail.api_key || Date.now()}.csv`);
  link.style.visibility = "hidden";
  document.body.appendChild(link);
  link.click();
  document.body.removeChild(link);
  ElMessage.success("CSV已下载");
}
</script>

<style scoped>
.app-container {
  padding: 20px;
}

.api-key-container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  word-break: break-all;
}

.api-key-detail {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
  word-break: break-all;
  gap: 8px;
}

.api-key-detail span {
  word-break: break-all;
  flex: 1;
  min-width: 0;
}

.config-loading-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 60px 0;
  color: #909399;
}

.config-loading-content .loading-icon {
  font-size: 32px;
  margin-bottom: 16px;
  animation: rotate 1s linear infinite;
}

@keyframes rotate {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}

.config-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 40px 0;
}

.docs-layout {
  display: flex;
  height: calc(100vh - 120px);
  gap: 20px;
}

.docs-sidebar {
  width: 280px;
  background-color: #f5f7fa;
  border-radius: 8px;
  padding: 20px 0;
  overflow: hidden;
}

.sidebar-section {
  margin-bottom: 24px;
  padding: 0 20px;
}

.sidebar-section h3 {
  font-size: 14px;
  font-weight: bold;
  color: #606266;
  margin-bottom: 12px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}

.sidebar-section ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.sidebar-section li {
  margin-bottom: 8px;
  padding: 8px 12px;
  border-radius: 4px;
  cursor: pointer;
  transition: all 0.3s ease;
  font-size: 14px;
  color: #606266;
}

.sidebar-section li:hover {
  background-color: #ecf5ff;
  color: #409eff;
}

.sidebar-section li.active {
  background-color: #ecf5ff;
  color: #409eff;
  font-weight: 500;
  border-left: 3px solid #409eff;
}

.docs-content {
  flex: 1;
  overflow-y: auto;
  padding: 0 20px;
}

.config-layout {
  padding: 20px;
}

.config-card {
  max-width: 700px;
}

.section-content {
  line-height: 1.6;
  padding: 20px 0;
}

.section-content h2 {
  margin-top: 0;
  margin-bottom: 20px;
  font-size: 20px;
  font-weight: bold;
  color: #303133;
}

.section-content h3 {
  margin-top: 24px;
  margin-bottom: 12px;
  font-size: 16px;
  font-weight: bold;
  color: #404145;
}

.section-content h4 {
  margin-top: 16px;
  margin-bottom: 8px;
  font-size: 14px;
  font-weight: bold;
  color: #606266;
}

.section-content p {
  margin-bottom: 12px;
  color: #606266;
}

.section-content ul,
.section-content ol {
  margin-left: 20px;
  margin-bottom: 16px;
  color: #606266;
}

.section-content li {
  margin-bottom: 6px;
}

.section-content pre {
  background-color: #f5f5f5;
  padding: 16px;
  border-radius: 4px;
  overflow-x: auto;
  margin-bottom: 16px;
  border: 1px solid #e4e7ed;
}

.section-content code {
  font-family: "Courier New", Courier, monospace;
  font-size: 14px;
  color: #303133;
}

.api-table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: 20px;
  border: 1px solid #e4e7ed;
  border-radius: 4px;
  overflow: hidden;
}

.api-table th,
.api-table td {
  border: 1px solid #e4e7ed;
  padding: 12px;
  text-align: left;
}

.api-table th {
  background-color: #f5f7fa;
  font-weight: bold;
  color: #303133;
}

.api-table tr:nth-child(even) {
  background-color: #fafafa;
}

.api-table tr:hover {
  background-color: #f5f7fa;
}

.nested-table {
  margin: 10px 0 0 20px;
  font-size: 13px;
}

.expandable-section {
  width: 100%;
}

.expand-btn {
  cursor: pointer;
  display: inline-block;
  font-weight: 500;
  color: #409eff;
  transition: all 0.3s ease;
}

.expand-btn:hover {
  color: #66b1ff;
}

.expandable-content {
  margin-top: 8px;
  padding-left: 20px;
  animation: slideDown 0.3s ease;
}

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

.card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 20px;
  /* border-bottom: 1px solid #e4e7ed; */
  margin: -20px -20px 20px -20px;
  /* background-color: #fafafa; */
}

.card-header span {
  font-size: 16px;
  font-weight: bold;
  color: #303133;
}
</style>
