This commit is contained in:
iqudoo
2026-05-25 11:42:34 +08:00
parent a74a20049a
commit 4ebe673885

View File

@@ -1,21 +1,14 @@
<template> <template>
<el-container <el-container :class="{ 'mobile-mode': isMobile }" v-loading="loading" element-loading-text="正在加载接口列表..."
:class="{ 'mobile-mode': isMobile }" element-loading-background="rgba(255, 255, 255, 1)">
v-loading="loading"
element-loading-text="正在加载接口列表..."
element-loading-background="rgba(255, 255, 255, 1)"
>
<el-header v-if="isMobile" class="mobile-header"> <el-header v-if="isMobile" class="mobile-header">
<el-button :icon="Menu" circle text class="menu-toggle-btn" @click="toggleMenu" /> <el-button :icon="Menu" circle text class="menu-toggle-btn" @click="toggleMenu" />
<h2>API 文档中心</h2> <h2>API 文档中心</h2>
<span class="mobile-header-spacer" /> <span class="mobile-header-spacer" />
</el-header> </el-header>
<el-aside <el-aside :width="isMobile ? '100%' : '280px'" class="sidebar"
:width="isMobile ? '100%' : '280px'" v-show="(!isMobile || (isMobile && showMenu)) && !loadError">
class="sidebar"
v-show="(!isMobile || (isMobile && showMenu)) && !loadError"
>
<div class="sidebar-inner"> <div class="sidebar-inner">
<div class="sidebar-header"> <div class="sidebar-header">
<div class="sidebar-brand"> <div class="sidebar-brand">
@@ -26,24 +19,12 @@
</span> </span>
</div> </div>
</div> </div>
<el-button <el-button v-if="isMobile" :icon="Close" circle text class="sidebar-close-btn" @click="toggleMenu" />
v-if="isMobile"
:icon="Close"
circle
text
class="sidebar-close-btn"
@click="toggleMenu"
/>
</div> </div>
<div class="sidebar-search"> <div class="sidebar-search">
<el-input <el-input placeholder="搜索接口..." v-model="searchQuery" clearable :prefix-icon="Search"
placeholder="搜索接口..." :disabled="loading || !!loadError" />
v-model="searchQuery"
clearable
:prefix-icon="Search"
:disabled="loading || !!loadError"
/>
</div> </div>
<div class="sidebar-content"> <div class="sidebar-content">
@@ -68,95 +49,69 @@
<div class="breadcrumb-path"> <div class="breadcrumb-path">
<span class="breadcrumb-tag breadcrumb-clickable" @click="goHome">根目录</span> <span class="breadcrumb-tag breadcrumb-clickable" @click="goHome">根目录</span>
<template v-for="(path, index) in currentPath" :key="index"> <template v-for="(path, index) in currentPath" :key="index">
<el-icon class="breadcrumb-chevron"><ArrowRight /></el-icon> <el-icon class="breadcrumb-chevron">
<span <ArrowRight />
class="breadcrumb-tag" </el-icon>
:class="{ <span class="breadcrumb-tag" :class="{
'breadcrumb-clickable': index < currentPath.length - 1, 'breadcrumb-clickable': index < currentPath.length - 1,
'breadcrumb-current': index === currentPath.length - 1, 'breadcrumb-current': index === currentPath.length - 1,
}" }" @click="index < currentPath.length - 1 && navigateToPath(index)">
@click="index < currentPath.length - 1 && navigateToPath(index)"
>
{{ path }} {{ path }}
</span> </span>
</template> </template>
</div> </div>
</div> </div>
<el-empty <el-empty v-if="
v-if="
!loading && !loading &&
!loadError && !loadError &&
currentLevelNodes.length === 0 && currentLevelNodes.length === 0 &&
currentLevelApis.length === 0 currentLevelApis.length === 0
" " description="没有找到相关接口" :image-size="64" class="sidebar-empty" />
description="没有找到相关接口"
:image-size="64"
class="sidebar-empty"
/>
<el-menu <el-menu v-else class="menu-vertical" :default-active="activeMenuIndex">
v-else
class="menu-vertical"
:default-active="activeMenuIndex"
>
<template v-for="node in currentLevelNodes" :key="node.key"> <template v-for="node in currentLevelNodes" :key="node.key">
<el-menu-item <el-menu-item v-if="
v-if="
!node.isUngrouped && (node.children.length > 0 || node.apis.length > 0) !node.isUngrouped && (node.children.length > 0 || node.apis.length > 0)
" " :index="node.key" @click="enterGroup(node)" class="menu-folder-item" :disabled="loading">
:index="node.key"
@click="enterGroup(node)"
class="menu-folder-item"
:disabled="loading"
>
<div class="menu-item-inner"> <div class="menu-item-inner">
<el-icon class="menu-item-icon folder"><Folder /></el-icon> <el-icon class="menu-item-icon folder">
<Folder />
</el-icon>
<span class="menu-item-label">{{ node.displayName }}</span> <span class="menu-item-label">{{ node.displayName }}</span>
<span class="menu-item-count">{{ getNodeApiCount(node) }}</span> <span class="menu-item-count">{{ getNodeApiCount(node) }}</span>
<el-icon class="menu-item-arrow"><ArrowRight /></el-icon> <el-icon class="menu-item-arrow">
<ArrowRight />
</el-icon>
</div> </div>
</el-menu-item> </el-menu-item>
<el-menu-item <el-menu-item v-else-if="node.isUngrouped" :index="node.key" @click="
v-else-if="node.isUngrouped"
:index="node.key"
@click="
goToApi(node.apis[0]); goToApi(node.apis[0]);
isMobile && toggleMenu(); isMobile && toggleMenu();
" " class="menu-api-item" :disabled="loading">
class="menu-api-item"
:disabled="loading"
>
<div class="menu-item-inner"> <div class="menu-item-inner">
<el-icon class="menu-item-icon api"><Document /></el-icon> <el-icon class="menu-item-icon api">
<Document />
</el-icon>
<span class="menu-item-label">{{ node.displayName }}</span> <span class="menu-item-label">{{ node.displayName }}</span>
</div> </div>
</el-menu-item> </el-menu-item>
</template> </template>
<template v-if="currentLevelApis.length > 0"> <template v-if="currentLevelApis.length > 0">
<el-menu-item <el-menu-item v-if="currentLevelNodes.length > 0" index="__section_apis__" disabled
v-if="currentLevelNodes.length > 0" class="menu-section-item">
index="__section_apis__"
disabled
class="menu-section-item"
>
<span class="menu-section-label">接口</span> <span class="menu-section-label">接口</span>
</el-menu-item> </el-menu-item>
<el-menu-item <el-menu-item v-for="api in currentLevelApis" :key="api.uniqueId" :index="api.uniqueId" @click="
v-for="api in currentLevelApis"
:key="api.uniqueId"
:index="api.uniqueId"
@click="
goToApi(api); goToApi(api);
isMobile && toggleMenu(); isMobile && toggleMenu();
" " class="menu-api-item" :disabled="loading">
class="menu-api-item"
:disabled="loading"
>
<div class="menu-item-inner"> <div class="menu-item-inner">
<el-icon class="menu-item-icon api"><Document /></el-icon> <el-icon class="menu-item-icon api">
<Document />
</el-icon>
<span class="menu-item-label">{{ <span class="menu-item-label">{{
getCurrentNodeApiDisplayName(api) getCurrentNodeApiDisplayName(api)
}}</span> }}</span>
@@ -184,28 +139,16 @@
<div class="content-nav-wrap"> <div class="content-nav-wrap">
<div class="content-section content-nav-bar"> <div class="content-section content-nav-bar">
<div class="content-nav-tabs"> <div class="content-nav-tabs">
<button <button type="button" class="content-nav-tab" :class="{ active: activeTab === 'docs' }"
type="button" @click="activeTab = 'docs'">
class="content-nav-tab"
:class="{ active: activeTab === 'docs' }"
@click="activeTab = 'docs'"
>
接口文档 接口文档
</button> </button>
<button <button type="button" class="content-nav-tab" :class="{ active: activeTab === 'common' }"
type="button" @click="activeTab = 'common'">
class="content-nav-tab"
:class="{ active: activeTab === 'common' }"
@click="activeTab = 'common'"
>
通用信息 通用信息
</button> </button>
</div> </div>
<el-button <el-button type="primary" :icon="Download" @click="showExportDrawer = true">
type="primary"
:icon="Download"
@click="showExportDrawer = true"
>
导出文档 导出文档
</el-button> </el-button>
</div> </div>
@@ -217,7 +160,9 @@
<div v-if="!currentApi" class="content-page readme-guide"> <div v-if="!currentApi" class="content-page readme-guide">
<div class="content-section page-header-card page-header-card-center"> <div class="content-section page-header-card page-header-card-center">
<div class="page-header-main"> <div class="page-header-main">
<el-icon class="page-hero-icon"><Document /></el-icon> <el-icon class="page-hero-icon">
<Document />
</el-icon>
<div> <div>
<h1 class="page-hero-title">接口文档中心</h1> <h1 class="page-hero-title">接口文档中心</h1>
<p class="page-hero-desc"> <p class="page-hero-desc">
@@ -283,10 +228,7 @@
</div> </div>
</div> </div>
<div <div v-if="currentApi" class="content-page api-detail">
v-if="currentApi"
class="content-page api-detail"
>
<div class="content-section page-header-card"> <div class="content-section page-header-card">
<div class="page-header-main"> <div class="page-header-main">
<div class="page-header-text"> <div class="page-header-text">
@@ -294,25 +236,14 @@
<h1 class="api-action-name">{{ currentApi.action }}</h1> <h1 class="api-action-name">{{ currentApi.action }}</h1>
</div> </div>
</div> </div>
<el-button <el-button type="primary" plain size="small" :icon="DocumentCopy"
type="primary" :disabled="apiDetailLoading || !apiDetail" @click="copyApiMarkdown">
plain
size="small"
:icon="DocumentCopy"
:disabled="apiDetailLoading || !apiDetail"
@click="copyApiMarkdown"
>
复制文档 复制文档
</el-button> </el-button>
</div> </div>
<div v-if="apiDetailError" class="api-detail-alert"> <div v-if="apiDetailError" class="api-detail-alert">
<el-alert <el-alert :title="apiDetailError" type="warning" :closable="false" show-icon />
:title="apiDetailError"
type="warning"
:closable="false"
show-icon
/>
</div> </div>
<div class="api-detail-body"> <div class="api-detail-body">
@@ -380,12 +311,10 @@
<p v-if="apiDetail.paramModel.basicProperty" class="basic-type-display"> <p v-if="apiDetail.paramModel.basicProperty" class="basic-type-display">
类型:{{ getFullTypeName(apiDetail.paramModel) }} 类型:{{ getFullTypeName(apiDetail.paramModel) }}
</p> </p>
<div <div v-for="model in getAllModels(apiDetail.paramModel)" :key="model.simpleName"
v-for="model in getAllModels(apiDetail.paramModel)" class="model-card">
:key="model.simpleName" <h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}
class="model-card" </h4>
>
<h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}</h4>
<!-- 桌面端表格布局 --> <!-- 桌面端表格布局 -->
<el-table v-if="!isMobile" :data="model.fields" class="data-table"> <el-table v-if="!isMobile" :data="model.fields" class="data-table">
@@ -403,20 +332,14 @@
{{ getTypeName(scope.row) }} {{ getTypeName(scope.row) }}
</template> </template>
&lt; &lt;
<template <template v-for="(param, index) in getGenericParams(scope.row)" :key="index">
v-for="(param, index) in getGenericParams(scope.row)"
:key="index"
>
<template v-if="param.isObject"> <template v-if="param.isObject">
<a :href="'#model-' + param.name">{{ param.name }}</a> <a :href="'#model-' + param.name">{{ param.name }}</a>
</template> </template>
<template v-else> <template v-else>
{{ param.name }} {{ param.name }}
</template> </template>
<template <template v-if="index < getGenericParams(scope.row).length - 1">,</template>
v-if="index < getGenericParams(scope.row).length - 1"
>,</template
>
</template> </template>
&gt; &gt;
</template> </template>
@@ -441,35 +364,19 @@
<el-table-column prop="desc" label="说明"> <el-table-column prop="desc" label="说明">
<template #default="scope"> <template #default="scope">
<div> <div>
<div v-if="scope.row.desc">{{ scope.row.desc }}</div> <span v-if="scope.row.desc" style="margin-right: 8px">{{ scope.row.desc }}</span>
<div <span v-if="scope.row.enumInfo && scope.row.enumInfo.properties">
v-if="scope.row.enumInfo && scope.row.enumInfo.properties" <span style="font-weight: bolder;color: #409eff;margin-right: 4px;">
style="margin-top: 8px" 枚举值
> </span>
<div <span v-html="scope.row.enumInfo.properties.map((item) => {
style="
font-weight: bolder;
color: #409eff;
margin-bottom: 4px;
"
>
枚举值:
</div>
<div
v-html="
scope.row.enumInfo.properties.map((item) => {
return `${item.desc}(${item.value})`; return `${item.desc}(${item.value})`;
}) }).join(', ')" style="color: #606266"></span>
" </span>
style="color: #606266" <div v-if="
></div>
</div>
<div
v-if="
!scope.row.desc && !scope.row.desc &&
!(scope.row.enumInfo && scope.row.enumInfo.properties) !(scope.row.enumInfo && scope.row.enumInfo.properties)
" ">
>
- -
</div> </div>
</div> </div>
@@ -501,20 +408,14 @@
{{ getTypeName(field) }} {{ getTypeName(field) }}
</template> </template>
&lt; &lt;
<template <template v-for="(param, index) in getGenericParams(field)" :key="index">
v-for="(param, index) in getGenericParams(field)"
:key="index"
>
<template v-if="param.isObject"> <template v-if="param.isObject">
<a :href="'#model-' + param.name">{{ param.name }}</a> <a :href="'#model-' + param.name">{{ param.name }}</a>
</template> </template>
<template v-else> <template v-else>
{{ param.name }} {{ param.name }}
</template> </template>
<template <template v-if="index < getGenericParams(field).length - 1">,</template>
v-if="index < getGenericParams(field).length - 1"
>,</template
>
</template> </template>
&gt; &gt;
</template> </template>
@@ -534,19 +435,12 @@
<div class="field-label">说明:</div> <div class="field-label">说明:</div>
<div class="field-value">{{ field.desc }}</div> <div class="field-value">{{ field.desc }}</div>
</div> </div>
<div <div class="field-item" v-if="field.enumInfo && field.enumInfo.properties">
class="field-item"
v-if="field.enumInfo && field.enumInfo.properties"
>
<div class="field-label">枚举值:</div> <div class="field-label">枚举值:</div>
<div class="field-value"> <div class="field-value">
<div <div v-html="field.enumInfo.properties.map((item) => {
v-html="
field.enumInfo.properties.map((item) => {
return `${item.desc}(${item.value})`; return `${item.desc}(${item.value})`;
}) }).join(', ')" style="color: #606266"></div>
"
></div>
</div> </div>
</div> </div>
</div> </div>
@@ -563,12 +457,10 @@
<p v-if="apiDetail.responseModel.basicProperty" class="basic-type-display"> <p v-if="apiDetail.responseModel.basicProperty" class="basic-type-display">
类型:{{ getFullTypeName(apiDetail.responseModel) }} 类型:{{ getFullTypeName(apiDetail.responseModel) }}
</p> </p>
<div <div v-for="model in getAllModels(apiDetail.responseModel)" :key="model.simpleName"
v-for="model in getAllModels(apiDetail.responseModel)" class="model-card">
:key="model.simpleName" <h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}
class="model-card" </h4>
>
<h4 :id="'model-' + model.simpleName" class="model-title">{{ getModelDisplayName(model) }}</h4>
<!-- 桌面端表格布局 --> <!-- 桌面端表格布局 -->
<el-table v-if="!isMobile" :data="model.fields" class="data-table"> <el-table v-if="!isMobile" :data="model.fields" class="data-table">
<el-table-column prop="name" label="参数名" width="auto" /> <el-table-column prop="name" label="参数名" width="auto" />
@@ -585,20 +477,14 @@
{{ getTypeName(scope.row) }} {{ getTypeName(scope.row) }}
</template> </template>
&lt; &lt;
<template <template v-for="(param, index) in getGenericParams(scope.row)" :key="index">
v-for="(param, index) in getGenericParams(scope.row)"
:key="index"
>
<template v-if="param.isObject"> <template v-if="param.isObject">
<a :href="'#model-' + param.name">{{ param.name }}</a> <a :href="'#model-' + param.name">{{ param.name }}</a>
</template> </template>
<template v-else> <template v-else>
{{ param.name }} {{ param.name }}
</template> </template>
<template <template v-if="index < getGenericParams(scope.row).length - 1">,</template>
v-if="index < getGenericParams(scope.row).length - 1"
>,</template
>
</template> </template>
&gt; &gt;
</template> </template>
@@ -618,35 +504,19 @@
<el-table-column prop="desc" label="说明"> <el-table-column prop="desc" label="说明">
<template #default="scope"> <template #default="scope">
<div> <div>
<div v-if="scope.row.desc">{{ scope.row.desc }}</div> <span v-if="scope.row.desc" style="margin-right: 8px">{{ scope.row.desc }}</span>
<div <span v-if="scope.row.enumInfo && scope.row.enumInfo.properties">
v-if="scope.row.enumInfo && scope.row.enumInfo.properties" <span style="font-weight: bolder;color: #409eff; margin-right: 4px;">
style="margin-top: 8px" 枚举值
> </span>
<div <span v-html="scope.row.enumInfo.properties.map((item) => {
style="
font-weight: bolder;
color: #409eff;
margin-bottom: 4px;
"
>
枚举值:
</div>
<div
v-html="
scope.row.enumInfo.properties.map((item) => {
return `${item.desc}(${item.value})`; return `${item.desc}(${item.value})`;
}) }).join(', ')" style="color: #606266"></span>
" </span>
style="color: #606266" <div v-if="
></div>
</div>
<div
v-if="
!scope.row.desc && !scope.row.desc &&
!(scope.row.enumInfo && scope.row.enumInfo.properties) !(scope.row.enumInfo && scope.row.enumInfo.properties)
" ">
>
- -
</div> </div>
</div> </div>
@@ -677,20 +547,14 @@
{{ getTypeName(field) }} {{ getTypeName(field) }}
</template> </template>
&lt; &lt;
<template <template v-for="(param, index) in getGenericParams(field)" :key="index">
v-for="(param, index) in getGenericParams(field)"
:key="index"
>
<template v-if="param.isObject"> <template v-if="param.isObject">
<a :href="'#model-' + param.name">{{ param.name }}</a> <a :href="'#model-' + param.name">{{ param.name }}</a>
</template> </template>
<template v-else> <template v-else>
{{ param.name }} {{ param.name }}
</template> </template>
<template <template v-if="index < getGenericParams(field).length - 1">,</template>
v-if="index < getGenericParams(field).length - 1"
>,</template
>
</template> </template>
&gt; &gt;
</template> </template>
@@ -710,19 +574,13 @@
<div class="field-label">说明:</div> <div class="field-label">说明:</div>
<div class="field-value">{{ field.desc }}</div> <div class="field-value">{{ field.desc }}</div>
</div> </div>
<div <div class="field-item" v-if="field.enumInfo && field.enumInfo.properties">
class="field-item"
v-if="field.enumInfo && field.enumInfo.properties"
>
<div class="field-label">枚举值:</div> <div class="field-label">枚举值:</div>
<div class="field-value"> <div class="field-value">
<div <div v-html="field.enumInfo.properties.map((item) => {
v-html="
field.enumInfo.properties.map((item) => {
return `${item.desc}(${item.value})`; return `${item.desc}(${item.value})`;
}) })
" "></div>
></div>
</div> </div>
</div> </div>
</div> </div>
@@ -763,11 +621,7 @@
<section class="content-section"> <section class="content-section">
<h3 class="section-title">通用请求参数</h3> <h3 class="section-title">通用请求参数</h3>
<el-table <el-table :data="commonParams" class="data-table" :class="{ 'responsive-table': isMobile }">
:data="commonParams"
class="data-table"
:class="{ 'responsive-table': isMobile }"
>
<el-table-column prop="name" label="参数名" width="auto" /> <el-table-column prop="name" label="参数名" width="auto" />
<el-table-column prop="required" label="必填" width="auto" /> <el-table-column prop="required" label="必填" width="auto" />
<el-table-column prop="desc" label="说明" /> <el-table-column prop="desc" label="说明" />
@@ -776,11 +630,7 @@
<section class="content-section"> <section class="content-section">
<h3 class="section-title">通用响应格式</h3> <h3 class="section-title">通用响应格式</h3>
<el-table <el-table :data="commonResponse" class="data-table" :class="{ 'responsive-table': isMobile }">
:data="commonResponse"
class="data-table"
:class="{ 'responsive-table': isMobile }"
>
<el-table-column prop="name" label="字段名" width="auto" /> <el-table-column prop="name" label="字段名" width="auto" />
<el-table-column prop="desc" label="说明" /> <el-table-column prop="desc" label="说明" />
</el-table> </el-table>
@@ -793,13 +643,7 @@
</el-main> </el-main>
</el-container> </el-container>
<el-drawer <el-drawer v-model="showExportDrawer" title="导出文档" direction="rtl" :size="exportDrawerSize" class="export-drawer">
v-model="showExportDrawer"
title="导出文档"
direction="rtl"
:size="exportDrawerSize"
class="export-drawer"
>
<div class="export-module"> <div class="export-module">
<p class="export-description"> <p class="export-description">
导出接口文档为 Markdown 格式,支持导出全部或按需选择 导出接口文档为 Markdown 格式,支持导出全部或按需选择
@@ -811,12 +655,7 @@
</template> </template>
<div class="quick-export-content"> <div class="quick-export-content">
<p class="quick-export-desc">一键导出所有接口文档</p> <p class="quick-export-desc">一键导出所有接口文档</p>
<el-button <el-button type="primary" @click="downloadApiDocumentation" :loading="downloading" style="width: 100%">
type="primary"
@click="downloadApiDocumentation"
:loading="downloading"
style="width: 100%"
>
{{ downloading ? "下载中..." : "下载全部接口文档" }} {{ downloading ? "下载中..." : "下载全部接口文档" }}
</el-button> </el-button>
</div> </div>
@@ -828,12 +667,7 @@
<p class="section-desc">选择需要导出的接口,生成自定义文档</p> <p class="section-desc">选择需要导出的接口,生成自定义文档</p>
</div> </div>
<div class="export-select-header"> <div class="export-select-header">
<el-input <el-input v-model="exportSearchQuery" placeholder="搜索接口" clearable :prefix-icon="Search" />
v-model="exportSearchQuery"
placeholder="搜索接口"
clearable
:prefix-icon="Search"
/>
<div class="select-actions"> <div class="select-actions">
<el-button type="primary" @click="selectAllExportApis">全选</el-button> <el-button type="primary" @click="selectAllExportApis">全选</el-button>
<el-button @click="deselectAllExportApis">取消全选</el-button> <el-button @click="deselectAllExportApis">取消全选</el-button>
@@ -843,33 +677,24 @@
</div> </div>
</div> </div>
<div class="export-api-list"> <div class="export-api-list">
<el-tree <el-tree ref="exportTreeRef" :data="exportTreeData" :props="exportTreeProps" show-checkbox node-key="id"
ref="exportTreeRef" :default-expand-all="false" :filter-node-method="filterExportNode" @check="handleExportTreeCheck">
:data="exportTreeData"
:props="exportTreeProps"
show-checkbox
node-key="id"
:default-expand-all="false"
:filter-node-method="filterExportNode"
@check="handleExportTreeCheck"
>
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="export-tree-node"> <span class="export-tree-node">
<el-icon v-if="data.isApi" class="api-icon"><Document /></el-icon> <el-icon v-if="data.isApi" class="api-icon">
<el-icon v-else class="folder-icon"><Folder /></el-icon> <Document />
</el-icon>
<el-icon v-else class="folder-icon">
<Folder />
</el-icon>
<span class="node-label">{{ node.label }}</span> <span class="node-label">{{ node.label }}</span>
</span> </span>
</template> </template>
</el-tree> </el-tree>
</div> </div>
<div class="export-actions"> <div class="export-actions">
<el-button <el-button type="primary" @click="handleExportSelected" :loading="downloading"
type="primary" :disabled="selectedApiIds.length === 0" style="width: 100%">
@click="handleExportSelected"
:loading="downloading"
:disabled="selectedApiIds.length === 0"
style="width: 100%"
>
{{ downloading ? "导出中..." : "导出所选文档" }} {{ downloading ? "导出中..." : "导出所选文档" }}
</el-button> </el-button>
</div> </div>
@@ -1151,7 +976,7 @@ onMounted(async () => {
if (id) { if (id) {
const apiToShow = findApiById(id); const apiToShow = findApiById(id);
if (apiToShow) { if (apiToShow) {
showApiDetail(apiToShow); goToApi(apiToShow);
} }
} }
} }
@@ -1182,7 +1007,7 @@ onMounted(async () => {
if (id) { if (id) {
const apiToShow = findApiById(id); const apiToShow = findApiById(id);
if (apiToShow) { if (apiToShow) {
showApiDetail(apiToShow); goToApi(apiToShow);
} }
} }
} catch (error) { } catch (error) {
@@ -1226,8 +1051,46 @@ const goHome = () => {
updateUrlParameter(null); updateUrlParameter(null);
}; };
// 在侧边栏树中查找 API 所在的目录路径
const findApiMenuPath = (api) => {
if (!api) return { pathKeys: [], pathNames: [] };
const search = (nodes, pathKeys, pathNames) => {
for (const node of nodes) {
if (node.apis?.some((item) => item.uniqueId === api.uniqueId)) {
if (node.isUngrouped) {
return { pathKeys: [], pathNames: [] };
}
return {
pathKeys: [...pathKeys, node.key],
pathNames: [...pathNames, node.displayName],
};
}
if (node.children?.length) {
const result = search(
node.children,
[...pathKeys, node.key],
[...pathNames, node.displayName]
);
if (result) return result;
}
}
return null;
};
return search(apiTree.value, [], []) || { pathKeys: [], pathNames: [] };
};
// 将左侧菜单导航到 API 所在目录
const navigateToApiInMenu = (api) => {
const { pathKeys, pathNames } = findApiMenuPath(api);
currentPathKeys.value = pathKeys;
currentPath.value = pathNames;
};
// 路由到指定API // 路由到指定API
const goToApi = (api) => { const goToApi = (api) => {
navigateToApiInMenu(api);
showApiDetail(api); showApiDetail(api);
updateUrlParameter(api.uniqueId); updateUrlParameter(api.uniqueId);
}; };
@@ -1293,8 +1156,7 @@ const generateCurlExample = (api) => {
-d '{ -d '{
"action": "${api.action}", "action": "${api.action}",
"token": "YOUR_TOKEN", "token": "YOUR_TOKEN",
"params": {${ "params": {${Object.entries(requiredParams)
Object.entries(requiredParams)
.map(([key, value]) => '\n "' + key + '": ' + JSON.stringify(value)) .map(([key, value]) => '\n "' + key + '": ' + JSON.stringify(value))
.join(",") || "" .join(",") || ""
} }
@@ -1316,8 +1178,7 @@ const generateJsExample = (api) => {
axios.post('API_URL', { axios.post('API_URL', {
action: '${api.action}', action: '${api.action}',
token: 'YOUR_TOKEN', token: 'YOUR_TOKEN',
params: {${ params: {${Object.entries(requiredParams)
Object.entries(requiredParams)
.map(([key, value]) => "\n " + key + ": " + JSON.stringify(value)) .map(([key, value]) => "\n " + key + ": " + JSON.stringify(value))
.join(",") || "" .join(",") || ""
} }
@@ -3089,6 +2950,7 @@ const handleExportSelected = async () => {
opacity: 0; opacity: 0;
transform: translateY(10px); transform: translateY(10px);
} }
to { to {
opacity: 1; opacity: 1;
transform: translateY(0); transform: translateY(0);
@@ -3159,6 +3021,7 @@ h4 {
} }
@media (max-width: 768px) { @media (max-width: 768px) {
.content-nav-wrap, .content-nav-wrap,
.content-page { .content-page {
padding-left: 16px; padding-left: 16px;
@@ -3596,6 +3459,7 @@ h4 {
:deep(.el-table__inner-wrapper:before) { :deep(.el-table__inner-wrapper:before) {
background-color: transparent; background-color: transparent;
} }
:deep(.el-collapse-item__wrap) { :deep(.el-collapse-item__wrap) {
border-bottom: none; border-bottom: none;
} }