Compare commits
2 Commits
6992ed6331
...
f898aa94d5
| Author | SHA1 | Date |
|---|---|---|
|
|
f898aa94d5 | |
|
|
bff90e2ea4 |
|
|
@ -13,7 +13,7 @@ dist
|
||||||
dist-ssr
|
dist-ssr
|
||||||
coverage
|
coverage
|
||||||
*.local
|
*.local
|
||||||
|
test_json
|
||||||
/cypress/videos/
|
/cypress/videos/
|
||||||
/cypress/screenshots/
|
/cypress/screenshots/
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,10 @@ const router = createRouter({
|
||||||
path: '/manager/login',
|
path: '/manager/login',
|
||||||
component: () => import('../views/Login.vue'),
|
component: () => import('../views/Login.vue'),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/doc',
|
||||||
|
component: () => import('../views/doc.vue'),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: '/home',
|
path: '/home',
|
||||||
component: () => import('../views/Layout.vue'),
|
component: () => import('../views/Layout.vue'),
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,221 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
import {post} from "@/utils/request.ts";
|
||||||
|
import {ref} from "vue";
|
||||||
|
function convertToTreeData(data: any, parentPath: string = '') {
|
||||||
|
const treeData: any[] = [];
|
||||||
|
|
||||||
|
for (const key in data) {
|
||||||
|
const item = data[key];
|
||||||
|
|
||||||
|
// ✅ 增加类型判断,防止无限递归
|
||||||
|
if (typeof item !== 'object' || item === null || Array.isArray(item)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentPath = parentPath ? `${parentPath}/${key}` : key;
|
||||||
|
|
||||||
|
if (item.path && item.comment) {
|
||||||
|
treeData.push({
|
||||||
|
label: `${item.comment} (${item.path})`,
|
||||||
|
path: item.path,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const children = convertToTreeData(item, currentPath);
|
||||||
|
treeData.push({
|
||||||
|
label: item.comment || key,
|
||||||
|
path: currentPath,
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return treeData;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 使用示例
|
||||||
|
const treeData = ref<any[]>([]);
|
||||||
|
|
||||||
|
post("doc/base/getCatalog").then((response: any) => {
|
||||||
|
let tree=convertToTreeData(response);
|
||||||
|
treeData.value = tree
|
||||||
|
});
|
||||||
|
let requestsList:any[]=[];
|
||||||
|
let responseList:any[]=[];
|
||||||
|
const handleNodeClick = (data: any) => {
|
||||||
|
if (!data.children || data.children.length === 0) {
|
||||||
|
post("doc/base/getApiInfo", {path: data.path}).then((res: any) => {
|
||||||
|
apiInfo.value=res;
|
||||||
|
let requests=res.requests;
|
||||||
|
requestsList=[];
|
||||||
|
getRequestTree(requests)
|
||||||
|
apiInfo.value.requests=requestsList;
|
||||||
|
responseList=[];
|
||||||
|
getResponseTree(res.response,0,data.path)
|
||||||
|
apiInfo.value.response=responseList;
|
||||||
|
|
||||||
|
})
|
||||||
|
// 在这里执行你的业务逻辑,例如跳转、请求详情等
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const getRequestTree = (requests: any[], level: number = 0): void => {
|
||||||
|
requests.forEach((request) => {
|
||||||
|
// 打印当前层级和请求路径或其他信息
|
||||||
|
request.level=level;
|
||||||
|
requestsList.push(request)
|
||||||
|
|
||||||
|
// 如果存在 children 并且是数组,则递归调用,层级 +1
|
||||||
|
if (request.children && Array.isArray(request.children)) {
|
||||||
|
getRequestTree(request.children, level + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const getResponseTree = (data: any, level: number = 0, parentKey: string = ''): void=> {
|
||||||
|
data.level=level;
|
||||||
|
responseList.push(data)
|
||||||
|
|
||||||
|
if (data.children && Array.isArray(data.children)) {
|
||||||
|
for (let i = 0; i < data.children.length; i++){
|
||||||
|
getResponseTree(data.children[i], level + 1, parentKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const apiInfo:any=ref(null);
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<div class="container">
|
||||||
|
<el-tree
|
||||||
|
class="tree"
|
||||||
|
:data="treeData"
|
||||||
|
:props="{ children: 'children', label: 'label' }"
|
||||||
|
@node-click="handleNodeClick"
|
||||||
|
/>
|
||||||
|
<div class="api-info-container" v-if="apiInfo">
|
||||||
|
<div class="apiInfo">
|
||||||
|
<div class="name">{{ apiInfo.comment }}</div>
|
||||||
|
<div class="path">{{ apiInfo.path }}</div>
|
||||||
|
<div class="request-wrapper">
|
||||||
|
<div class="tip">请求参数</div>
|
||||||
|
<div class="request" v-for="item in apiInfo.requests">
|
||||||
|
<div class="offset" :key="item.path" :style="{ paddingLeft: item.level * 20 + 'px' }"></div>
|
||||||
|
<div class="name">{{ item.name }}</div>
|
||||||
|
<div class="comment">{{ item.comment }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="responses" v-if="apiInfo.response && apiInfo.response.length">
|
||||||
|
<div class="tip">响应参数</div>
|
||||||
|
<div
|
||||||
|
class="response"
|
||||||
|
v-for="item in apiInfo.response"
|
||||||
|
>
|
||||||
|
<div class="offset" :key="item.path" :style="{ paddingLeft: item.level * 20 + 'px' }"></div>
|
||||||
|
<div class="name">{{ item.name }}</div>
|
||||||
|
<div class="comment">{{ item.comment }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.container {
|
||||||
|
display: flex;
|
||||||
|
height: 100vh;
|
||||||
|
background-color: #f5f7fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tree {
|
||||||
|
width: 300px;
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-right: 1px solid #e4e7ed;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
:deep(.el-tree-node__content) {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
padding-left: 10px !important;
|
||||||
|
|
||||||
|
.el-tree-node__label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree-node.is-current > .el-tree-node__content) {
|
||||||
|
background-color: #ecf5ff;
|
||||||
|
border-right: 2px solid #409EFF;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.api-info-container {
|
||||||
|
flex: 1;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.apiInfo {
|
||||||
|
background-color: #fff;
|
||||||
|
border-radius: 8px;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
|
||||||
|
padding: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
.name {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #1a1a1a;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.path {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #f0f3f6;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.request-wrapper,
|
||||||
|
.responses {
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.request,
|
||||||
|
.response {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 8px 0;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.offset {
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.name {
|
||||||
|
width: 150px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.comment {
|
||||||
|
flex: 1;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Loading…
Reference in New Issue