fff
This commit is contained in:
434
src/App.vue
434
src/App.vue
@@ -1,21 +1,14 @@
|
||||
<template>
|
||||
<el-container
|
||||
:class="{ 'mobile-mode': isMobile }"
|
||||
v-loading="loading"
|
||||
element-loading-text="正在加载接口列表..."
|
||||
element-loading-background="rgba(255, 255, 255, 1)"
|
||||
>
|
||||
<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"
|
||||
>
|
||||
<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">
|
||||
@@ -26,24 +19,12 @@
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<el-button
|
||||
v-if="isMobile"
|
||||
:icon="Close"
|
||||
circle
|
||||
text
|
||||
class="sidebar-close-btn"
|
||||
@click="toggleMenu"
|
||||
/>
|
||||
<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"
|
||||
/>
|
||||
<el-input placeholder="搜索接口..." v-model="searchQuery" clearable :prefix-icon="Search"
|
||||
:disabled="loading || !!loadError" />
|
||||
</div>
|
||||
|
||||
<div class="sidebar-content">
|
||||
@@ -68,95 +49,69 @@
|
||||
<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="{
|
||||
<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)"
|
||||
>
|
||||
}" @click="index < currentPath.length - 1 && navigateToPath(index)">
|
||||
{{ path }}
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-empty
|
||||
v-if="
|
||||
<el-empty v-if="
|
||||
!loading &&
|
||||
!loadError &&
|
||||
currentLevelNodes.length === 0 &&
|
||||
currentLevelApis.length === 0
|
||||
"
|
||||
description="没有找到相关接口"
|
||||
:image-size="64"
|
||||
class="sidebar-empty"
|
||||
/>
|
||||
" description="没有找到相关接口" :image-size="64" class="sidebar-empty" />
|
||||
|
||||
<el-menu
|
||||
v-else
|
||||
class="menu-vertical"
|
||||
:default-active="activeMenuIndex"
|
||||
>
|
||||
<el-menu v-else class="menu-vertical" :default-active="activeMenuIndex">
|
||||
<template v-for="node in currentLevelNodes" :key="node.key">
|
||||
<el-menu-item
|
||||
v-if="
|
||||
<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"
|
||||
>
|
||||
" :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>
|
||||
<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>
|
||||
<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="
|
||||
<el-menu-item v-else-if="node.isUngrouped" :index="node.key" @click="
|
||||
goToApi(node.apis[0]);
|
||||
isMobile && toggleMenu();
|
||||
"
|
||||
class="menu-api-item"
|
||||
:disabled="loading"
|
||||
>
|
||||
" class="menu-api-item" :disabled="loading">
|
||||
<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>
|
||||
</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"
|
||||
>
|
||||
<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="
|
||||
<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"
|
||||
>
|
||||
" class="menu-api-item" :disabled="loading">
|
||||
<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">{{
|
||||
getCurrentNodeApiDisplayName(api)
|
||||
}}</span>
|
||||
@@ -184,28 +139,16 @@
|
||||
<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 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 type="button" class="content-nav-tab" :class="{ active: activeTab === 'common' }"
|
||||
@click="activeTab = 'common'">
|
||||
通用信息
|
||||
</button>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
:icon="Download"
|
||||
@click="showExportDrawer = true"
|
||||
>
|
||||
<el-button type="primary" :icon="Download" @click="showExportDrawer = true">
|
||||
导出文档
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -217,7 +160,9 @@
|
||||
<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>
|
||||
<el-icon class="page-hero-icon">
|
||||
<Document />
|
||||
</el-icon>
|
||||
<div>
|
||||
<h1 class="page-hero-title">接口文档中心</h1>
|
||||
<p class="page-hero-desc">
|
||||
@@ -283,10 +228,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="currentApi"
|
||||
class="content-page api-detail"
|
||||
>
|
||||
<div v-if="currentApi" class="content-page api-detail">
|
||||
<div class="content-section page-header-card">
|
||||
<div class="page-header-main">
|
||||
<div class="page-header-text">
|
||||
@@ -294,25 +236,14 @@
|
||||
<h1 class="api-action-name">{{ currentApi.action }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
size="small"
|
||||
:icon="DocumentCopy"
|
||||
:disabled="apiDetailLoading || !apiDetail"
|
||||
@click="copyApiMarkdown"
|
||||
>
|
||||
<el-button type="primary" plain size="small" :icon="DocumentCopy"
|
||||
:disabled="apiDetailLoading || !apiDetail" @click="copyApiMarkdown">
|
||||
复制文档
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-if="apiDetailError" class="api-detail-alert">
|
||||
<el-alert
|
||||
:title="apiDetailError"
|
||||
type="warning"
|
||||
:closable="false"
|
||||
show-icon
|
||||
/>
|
||||
<el-alert :title="apiDetailError" type="warning" :closable="false" show-icon />
|
||||
</div>
|
||||
|
||||
<div class="api-detail-body">
|
||||
@@ -380,12 +311,10 @@
|
||||
<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>
|
||||
<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">
|
||||
@@ -403,20 +332,14 @@
|
||||
{{ getTypeName(scope.row) }}
|
||||
</template>
|
||||
<
|
||||
<template
|
||||
v-for="(param, index) in getGenericParams(scope.row)"
|
||||
:key="index"
|
||||
>
|
||||
<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 v-if="index < getGenericParams(scope.row).length - 1">,</template>
|
||||
</template>
|
||||
>
|
||||
</template>
|
||||
@@ -441,35 +364,19 @@
|
||||
<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) => {
|
||||
<span v-if="scope.row.desc" style="margin-right: 8px">{{ scope.row.desc }}</span>
|
||||
<span v-if="scope.row.enumInfo && scope.row.enumInfo.properties">
|
||||
<span style="font-weight: bolder;color: #409eff;margin-right: 4px;">
|
||||
枚举值
|
||||
</span>
|
||||
<span v-html="scope.row.enumInfo.properties.map((item) => {
|
||||
return `${item.desc}(${item.value})`;
|
||||
})
|
||||
"
|
||||
style="color: #606266"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
}).join(', ')" style="color: #606266"></span>
|
||||
</span>
|
||||
<div v-if="
|
||||
!scope.row.desc &&
|
||||
!(scope.row.enumInfo && scope.row.enumInfo.properties)
|
||||
"
|
||||
>
|
||||
">
|
||||
-
|
||||
</div>
|
||||
</div>
|
||||
@@ -501,20 +408,14 @@
|
||||
{{ getTypeName(field) }}
|
||||
</template>
|
||||
<
|
||||
<template
|
||||
v-for="(param, index) in getGenericParams(field)"
|
||||
:key="index"
|
||||
>
|
||||
<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 v-if="index < getGenericParams(field).length - 1">,</template>
|
||||
</template>
|
||||
>
|
||||
</template>
|
||||
@@ -534,19 +435,12 @@
|
||||
<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-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) => {
|
||||
<div v-html="field.enumInfo.properties.map((item) => {
|
||||
return `${item.desc}(${item.value})`;
|
||||
})
|
||||
"
|
||||
></div>
|
||||
}).join(', ')" style="color: #606266"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -563,12 +457,10 @@
|
||||
<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>
|
||||
<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" />
|
||||
@@ -585,20 +477,14 @@
|
||||
{{ getTypeName(scope.row) }}
|
||||
</template>
|
||||
<
|
||||
<template
|
||||
v-for="(param, index) in getGenericParams(scope.row)"
|
||||
:key="index"
|
||||
>
|
||||
<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 v-if="index < getGenericParams(scope.row).length - 1">,</template>
|
||||
</template>
|
||||
>
|
||||
</template>
|
||||
@@ -618,35 +504,19 @@
|
||||
<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) => {
|
||||
<span v-if="scope.row.desc" style="margin-right: 8px">{{ scope.row.desc }}</span>
|
||||
<span v-if="scope.row.enumInfo && scope.row.enumInfo.properties">
|
||||
<span style="font-weight: bolder;color: #409eff; margin-right: 4px;">
|
||||
枚举值
|
||||
</span>
|
||||
<span v-html="scope.row.enumInfo.properties.map((item) => {
|
||||
return `${item.desc}(${item.value})`;
|
||||
})
|
||||
"
|
||||
style="color: #606266"
|
||||
></div>
|
||||
</div>
|
||||
<div
|
||||
v-if="
|
||||
}).join(', ')" style="color: #606266"></span>
|
||||
</span>
|
||||
<div v-if="
|
||||
!scope.row.desc &&
|
||||
!(scope.row.enumInfo && scope.row.enumInfo.properties)
|
||||
"
|
||||
>
|
||||
">
|
||||
-
|
||||
</div>
|
||||
</div>
|
||||
@@ -677,20 +547,14 @@
|
||||
{{ getTypeName(field) }}
|
||||
</template>
|
||||
<
|
||||
<template
|
||||
v-for="(param, index) in getGenericParams(field)"
|
||||
:key="index"
|
||||
>
|
||||
<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 v-if="index < getGenericParams(field).length - 1">,</template>
|
||||
</template>
|
||||
>
|
||||
</template>
|
||||
@@ -710,19 +574,13 @@
|
||||
<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-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) => {
|
||||
<div v-html="field.enumInfo.properties.map((item) => {
|
||||
return `${item.desc}(${item.value})`;
|
||||
})
|
||||
"
|
||||
></div>
|
||||
"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -763,11 +621,7 @@
|
||||
|
||||
<section class="content-section">
|
||||
<h3 class="section-title">通用请求参数</h3>
|
||||
<el-table
|
||||
:data="commonParams"
|
||||
class="data-table"
|
||||
:class="{ 'responsive-table': isMobile }"
|
||||
>
|
||||
<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="说明" />
|
||||
@@ -776,11 +630,7 @@
|
||||
|
||||
<section class="content-section">
|
||||
<h3 class="section-title">通用响应格式</h3>
|
||||
<el-table
|
||||
:data="commonResponse"
|
||||
class="data-table"
|
||||
:class="{ 'responsive-table': isMobile }"
|
||||
>
|
||||
<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>
|
||||
@@ -793,13 +643,7 @@
|
||||
</el-main>
|
||||
</el-container>
|
||||
|
||||
<el-drawer
|
||||
v-model="showExportDrawer"
|
||||
title="导出文档"
|
||||
direction="rtl"
|
||||
:size="exportDrawerSize"
|
||||
class="export-drawer"
|
||||
>
|
||||
<el-drawer v-model="showExportDrawer" title="导出文档" direction="rtl" :size="exportDrawerSize" class="export-drawer">
|
||||
<div class="export-module">
|
||||
<p class="export-description">
|
||||
导出接口文档为 Markdown 格式,支持导出全部或按需选择
|
||||
@@ -811,12 +655,7 @@
|
||||
</template>
|
||||
<div class="quick-export-content">
|
||||
<p class="quick-export-desc">一键导出所有接口文档</p>
|
||||
<el-button
|
||||
type="primary"
|
||||
@click="downloadApiDocumentation"
|
||||
:loading="downloading"
|
||||
style="width: 100%"
|
||||
>
|
||||
<el-button type="primary" @click="downloadApiDocumentation" :loading="downloading" style="width: 100%">
|
||||
{{ downloading ? "下载中..." : "下载全部接口文档" }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -828,12 +667,7 @@
|
||||
<p class="section-desc">选择需要导出的接口,生成自定义文档</p>
|
||||
</div>
|
||||
<div class="export-select-header">
|
||||
<el-input
|
||||
v-model="exportSearchQuery"
|
||||
placeholder="搜索接口"
|
||||
clearable
|
||||
:prefix-icon="Search"
|
||||
/>
|
||||
<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>
|
||||
@@ -843,33 +677,24 @@
|
||||
</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"
|
||||
>
|
||||
<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>
|
||||
<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%"
|
||||
>
|
||||
<el-button type="primary" @click="handleExportSelected" :loading="downloading"
|
||||
:disabled="selectedApiIds.length === 0" style="width: 100%">
|
||||
{{ downloading ? "导出中..." : "导出所选文档" }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -1151,7 +976,7 @@ onMounted(async () => {
|
||||
if (id) {
|
||||
const apiToShow = findApiById(id);
|
||||
if (apiToShow) {
|
||||
showApiDetail(apiToShow);
|
||||
goToApi(apiToShow);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1182,7 +1007,7 @@ onMounted(async () => {
|
||||
if (id) {
|
||||
const apiToShow = findApiById(id);
|
||||
if (apiToShow) {
|
||||
showApiDetail(apiToShow);
|
||||
goToApi(apiToShow);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
@@ -1226,8 +1051,46 @@ const goHome = () => {
|
||||
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
|
||||
const goToApi = (api) => {
|
||||
navigateToApiInMenu(api);
|
||||
showApiDetail(api);
|
||||
updateUrlParameter(api.uniqueId);
|
||||
};
|
||||
@@ -1293,8 +1156,7 @@ const generateCurlExample = (api) => {
|
||||
-d '{
|
||||
"action": "${api.action}",
|
||||
"token": "YOUR_TOKEN",
|
||||
"params": {${
|
||||
Object.entries(requiredParams)
|
||||
"params": {${Object.entries(requiredParams)
|
||||
.map(([key, value]) => '\n "' + key + '": ' + JSON.stringify(value))
|
||||
.join(",") || ""
|
||||
}
|
||||
@@ -1316,8 +1178,7 @@ const generateJsExample = (api) => {
|
||||
axios.post('API_URL', {
|
||||
action: '${api.action}',
|
||||
token: 'YOUR_TOKEN',
|
||||
params: {${
|
||||
Object.entries(requiredParams)
|
||||
params: {${Object.entries(requiredParams)
|
||||
.map(([key, value]) => "\n " + key + ": " + JSON.stringify(value))
|
||||
.join(",") || ""
|
||||
}
|
||||
@@ -3089,6 +2950,7 @@ const handleExportSelected = async () => {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
@@ -3159,6 +3021,7 @@ h4 {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
|
||||
.content-nav-wrap,
|
||||
.content-page {
|
||||
padding-left: 16px;
|
||||
@@ -3596,6 +3459,7 @@ h4 {
|
||||
:deep(.el-table__inner-wrapper:before) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
:deep(.el-collapse-item__wrap) {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user