feat: add docs build action

This commit is contained in:
engigu
2026-03-10 20:12:07 +08:00
parent 6d61c18539
commit 96e792c979
27 changed files with 4111 additions and 4176 deletions
+9
View File
@@ -30,6 +30,15 @@ jobs:
cache: 'npm'
cache-dependency-path: docs/package-lock.json
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.24'
cache: true
- name: Generate Swagger Docs
run: make swag
- name: Setup Pages
uses: actions/configure-pages@v4
+9
View File
@@ -50,3 +50,12 @@ __pycache__/
bin/
*.log
# VitePress
docs/.vitepress/cache/
docs/node_modules/
docs/public/swagger.json
docs/public/swagger.yaml
# OpenAPI
openapi_docs/
+11 -2
View File
@@ -111,7 +111,14 @@ deps:
# Generate swagger documentation
swag:
go run github.com/swaggo/swag/cmd/swag@latest init -g main.go -o ./openapi_docs
@mkdir -p docs/public
go run github.com/swaggo/swag/cmd/swag@latest init -g main.go -o ./docs/public --ot json,yaml
docs-dev:
cd docs && npm run docs:dev
docs-build:
cd docs && npm run docs:build
# Docker build
docker-build:
@@ -169,5 +176,7 @@ help:
@echo " docker-dev-d - Start isolated Docker dev environment (background)"
@echo " docker-dev-down - Stop Docker dev environment (keep caches)"
@echo " docker-dev-clean - Stop and clean Docker dev environment (remove caches)"
@echo " swag - Generate swagger documentation"
@echo " swag - Generate swagger documentation and sync with docs"
@echo " docs-dev - Run documentation development server"
@echo " docs-build - Build documentation"
@echo " help - Show this help message"
+31 -30
View File
@@ -7,40 +7,41 @@ import {
shallowRef,
watch
} from "./chunk-P622L5TS.js";
import "./chunk-DC5AMYBS.js";
// node_modules/vitepress/dist/client/theme-default/index.js
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/fonts.css";
// node_modules/vitepress/dist/client/theme-default/without-fonts.js
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default4 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default5 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
import { default as default6 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
import { default as default7 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default8 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default9 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default10 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default11 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
import { default as default12 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
import { default as default13 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
import { default as default14 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
import { default as default15 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default16 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
import { default as default17 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default18 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default19 } from "F:/workspace/baihu2/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/vars.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/base.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/icons.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/utils.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/components/custom-block.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-code-group.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-doc.css";
import "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/styles/components/vp-sponsor.css";
import VPBadge from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import Layout from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/Layout.vue";
import { default as default2 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPBadge.vue";
import { default as default3 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPButton.vue";
import { default as default4 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPDocAsideSponsors.vue";
import { default as default5 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPFeatures.vue";
import { default as default6 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeContent.vue";
import { default as default7 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeFeatures.vue";
import { default as default8 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeHero.vue";
import { default as default9 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPHomeSponsors.vue";
import { default as default10 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPImage.vue";
import { default as default11 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPLink.vue";
import { default as default12 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPNavBarSearch.vue";
import { default as default13 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPSocialLink.vue";
import { default as default14 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPSocialLinks.vue";
import { default as default15 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPSponsors.vue";
import { default as default16 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamMembers.vue";
import { default as default17 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPage.vue";
import { default as default18 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageSection.vue";
import { default as default19 } from "/Users/sayheya/workspace/own/baihu/docs/node_modules/vitepress/dist/client/theme-default/components/VPTeamPageTitle.vue";
// node_modules/vitepress/dist/client/theme-default/composables/local-nav.js
import { onContentUpdated } from "vitepress";
File diff suppressed because one or more lines are too long
+194 -11
View File
@@ -1,58 +1,241 @@
{
"hash": "c1e79c58",
"configHash": "bc8361ef",
"lockfileHash": "c12d42b4",
"browserHash": "50d21c6b",
"hash": "6de08870",
"configHash": "1066fa69",
"lockfileHash": "3eb5b4ef",
"browserHash": "ea2c25ee",
"optimized": {
"vue": {
"src": "../../../node_modules/vue/dist/vue.runtime.esm-bundler.js",
"file": "vue.js",
"fileHash": "a184effb",
"fileHash": "432b139f",
"needsInterop": false
},
"vitepress > @vue/devtools-api": {
"src": "../../../node_modules/@vue/devtools-api/dist/index.js",
"file": "vitepress___@vue_devtools-api.js",
"fileHash": "710eaece",
"fileHash": "68eb4127",
"needsInterop": false
},
"vitepress > @vueuse/core": {
"src": "../../../node_modules/@vueuse/core/index.mjs",
"file": "vitepress___@vueuse_core.js",
"fileHash": "34e9305a",
"fileHash": "c6a1e7fe",
"needsInterop": false
},
"vitepress > @vueuse/integrations/useFocusTrap": {
"src": "../../../node_modules/@vueuse/integrations/useFocusTrap.mjs",
"file": "vitepress___@vueuse_integrations_useFocusTrap.js",
"fileHash": "24943145",
"fileHash": "7b5b0568",
"needsInterop": false
},
"vitepress > mark.js/src/vanilla.js": {
"src": "../../../node_modules/mark.js/src/vanilla.js",
"file": "vitepress___mark__js_src_vanilla__js.js",
"fileHash": "ab1af925",
"fileHash": "8dab363d",
"needsInterop": false
},
"vitepress > minisearch": {
"src": "../../../node_modules/minisearch/dist/es/index.js",
"file": "vitepress___minisearch.js",
"fileHash": "6d234334",
"fileHash": "b7c74dbc",
"needsInterop": false
},
"@theme/index": {
"src": "../../../node_modules/vitepress/dist/client/theme-default/index.js",
"file": "@theme_index.js",
"fileHash": "e4dc0002",
"fileHash": "472b2329",
"needsInterop": false
},
"@scalar/api-reference": {
"src": "../../../node_modules/@scalar/api-reference/dist/index.js",
"file": "@scalar_api-reference.js",
"fileHash": "6dbb9b23",
"needsInterop": false
}
},
"chunks": {
"CollectionScripts.vue-LCLMS2F3": {
"file": "CollectionScripts__vue-LCLMS2F3.js"
},
"CollectionSync.vue-HXZ4AKU2": {
"file": "CollectionSync__vue-HXZ4AKU2.js"
},
"CollectionSettings.vue-EVBE7Z6D": {
"file": "CollectionSettings__vue-EVBE7Z6D.js"
},
"Environment.vue-6UBXLDGC": {
"file": "Environment__vue-6UBXLDGC.js"
},
"Cookies.vue-EXYHHBOZ": {
"file": "Cookies__vue-EXYHHBOZ.js"
},
"chunk-GZMNX6AX": {
"file": "chunk-GZMNX6AX.js"
},
"Settings.vue-PB7S5SG7": {
"file": "Settings__vue-PB7S5SG7.js"
},
"AgentScalarChatInterface.vue-INHYBGYV": {
"file": "AgentScalarChatInterface__vue-INHYBGYV.js"
},
"RequestRoot.vue-L3VYMGK2": {
"file": "RequestRoot__vue-L3VYMGK2.js"
},
"chunk-NEEM3NXU": {
"file": "chunk-NEEM3NXU.js"
},
"Request.vue-7L4P46QD": {
"file": "Request__vue-7L4P46QD.js"
},
"chunk-ISBQHWWE": {
"file": "chunk-ISBQHWWE.js"
},
"chunk-3IZMAJB2": {
"file": "chunk-3IZMAJB2.js"
},
"Collection.vue-FC2UI66A": {
"file": "Collection__vue-FC2UI66A.js"
},
"chunk-NDCSVEN3": {
"file": "chunk-NDCSVEN3.js"
},
"CollectionOverview.vue-G236GW75": {
"file": "CollectionOverview__vue-G236GW75.js"
},
"CollectionServers.vue-YN5WQWOE": {
"file": "CollectionServers__vue-YN5WQWOE.js"
},
"chunk-6S3GL5L7": {
"file": "chunk-6S3GL5L7.js"
},
"CollectionEnvironment.vue-FDJX3YDU": {
"file": "CollectionEnvironment__vue-FDJX3YDU.js"
},
"chunk-WYA3XXFI": {
"file": "chunk-WYA3XXFI.js"
},
"chunk-IGGURL24": {
"file": "chunk-IGGURL24.js"
},
"chunk-I5LUS3ED": {
"file": "chunk-I5LUS3ED.js"
},
"chunk-65DUN63O": {
"file": "chunk-65DUN63O.js"
},
"CollectionAuthentication.vue-KGN43T2P": {
"file": "CollectionAuthentication__vue-KGN43T2P.js"
},
"chunk-YKHL6VQC": {
"file": "chunk-YKHL6VQC.js"
},
"chunk-QQAZCTHR": {
"file": "chunk-QQAZCTHR.js"
},
"CollectionCookies.vue-FELY62F6": {
"file": "CollectionCookies__vue-FELY62F6.js"
},
"chunk-4BN7IBKA": {
"file": "chunk-4BN7IBKA.js"
},
"chunk-44U5TZV3": {
"file": "chunk-44U5TZV3.js"
},
"chunk-XX2G763M": {
"file": "chunk-XX2G763M.js"
},
"chunk-D335FA7A": {
"file": "chunk-D335FA7A.js"
},
"chunk-GCZHIOTH": {
"file": "chunk-GCZHIOTH.js"
},
"chunk-CWL3D5RK": {
"file": "chunk-CWL3D5RK.js"
},
"chunk-DZ6K3YTP": {
"file": "chunk-DZ6K3YTP.js"
},
"chunk-I763OZCO": {
"file": "chunk-I763OZCO.js"
},
"chunk-MNUNX6PP": {
"file": "chunk-MNUNX6PP.js"
},
"chunk-TPSA5WWY": {
"file": "chunk-TPSA5WWY.js"
},
"chunk-N6YYDONG": {
"file": "chunk-N6YYDONG.js"
},
"chunk-2KUFNJSH": {
"file": "chunk-2KUFNJSH.js"
},
"chunk-INVRMX7P": {
"file": "chunk-INVRMX7P.js"
},
"chunk-RYLNO5GS": {
"file": "chunk-RYLNO5GS.js"
},
"chunk-72ZKYODS": {
"file": "chunk-72ZKYODS.js"
},
"chunk-I7772QGA": {
"file": "chunk-I7772QGA.js"
},
"chunk-ROY6IE7D": {
"file": "chunk-ROY6IE7D.js"
},
"chunk-J2LCATIX": {
"file": "chunk-J2LCATIX.js"
},
"chunk-4IEXP2EA": {
"file": "chunk-4IEXP2EA.js"
},
"chunk-E6HBIPYF": {
"file": "chunk-E6HBIPYF.js"
},
"chunk-EZ4NNG5Z": {
"file": "chunk-EZ4NNG5Z.js"
},
"chunk-SG3AQALI": {
"file": "chunk-SG3AQALI.js"
},
"chunk-R3JJTOAQ": {
"file": "chunk-R3JJTOAQ.js"
},
"chunk-65OGKZZE": {
"file": "chunk-65OGKZZE.js"
},
"chunk-BLWTWMBJ": {
"file": "chunk-BLWTWMBJ.js"
},
"chunk-D7CWH7CX": {
"file": "chunk-D7CWH7CX.js"
},
"chunk-LL57R4AL": {
"file": "chunk-LL57R4AL.js"
},
"chunk-6LVYDRH4": {
"file": "chunk-6LVYDRH4.js"
},
"chunk-A6F3BLKW": {
"file": "chunk-A6F3BLKW.js"
},
"chunk-DNWW44OK": {
"file": "chunk-DNWW44OK.js"
},
"chunk-M5D4FP2Q": {
"file": "chunk-M5D4FP2Q.js"
},
"chunk-YNJBICHS": {
"file": "chunk-YNJBICHS.js"
},
"chunk-P622L5TS": {
"file": "chunk-P622L5TS.js"
},
"chunk-DC5AMYBS": {
"file": "chunk-DC5AMYBS.js"
}
}
}
@@ -1,3 +1,5 @@
import "./chunk-DC5AMYBS.js";
// node_modules/@vue/devtools-shared/dist/index.js
var __create = Object.create;
var __defProp = Object.defineProperty;
File diff suppressed because one or more lines are too long
@@ -283,6 +283,7 @@ import {
whenever
} from "./chunk-YNJBICHS.js";
import "./chunk-P622L5TS.js";
import "./chunk-DC5AMYBS.js";
export {
DefaultMagicKeysAliasMap,
StorageSerializers,
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -1,3 +1,5 @@
import "./chunk-DC5AMYBS.js";
// node_modules/mark.js/src/lib/domiterator.js
var DOMIterator = class _DOMIterator {
/**
File diff suppressed because one or more lines are too long
+2
View File
@@ -1,3 +1,5 @@
import "./chunk-DC5AMYBS.js";
// node_modules/minisearch/dist/es/index.js
var ENTRIES = "ENTRIES";
var KEYS = "KEYS";
File diff suppressed because one or more lines are too long
+1
View File
@@ -171,6 +171,7 @@ import {
withModifiers,
withScopeId
} from "./chunk-P622L5TS.js";
import "./chunk-DC5AMYBS.js";
export {
BaseTransition,
BaseTransitionPropsValidators,
+9 -2
View File
@@ -11,7 +11,8 @@ export default defineConfig({
logo: '/logo.svg',
nav: [
{ text: '指南', link: '/guide/introduction' },
{ text: '部署', link: '/guide/deployment' }
{ text: '部署', link: '/guide/deployment' },
{ text: 'API接口', link: '/guide/api' }
],
sidebar: [
@@ -20,7 +21,8 @@ export default defineConfig({
items: [
{ text: '项目介绍', link: '/guide/introduction' },
{ text: '快速部署', link: '/guide/deployment' },
{ text: '访问面板', link: '/guide/getting-started' }
{ text: '访问面板', link: '/guide/getting-started' },
{ text: 'API 接口', link: '/guide/api' }
]
},
{
@@ -59,5 +61,10 @@ export default defineConfig({
search: {
provider: 'local'
}
},
vite: {
ssr: {
noExternal: ['@scalar/api-reference']
}
}
})
+40
View File
@@ -0,0 +1,40 @@
---
layout: false
---
<script setup>
import { ApiReference } from '@scalar/api-reference'
import '@scalar/api-reference/style.css'
</script>
<div class="scalar-container">
<ClientOnly>
<ApiReference
:configuration="{
spec: {
url: '/baihu-panel/swagger.json'
},
theme: 'purple',
showSidebar: true
}"
/>
</ClientOnly>
</div>
<style>
:root, body, #app {
margin: 0;
padding: 0;
height: 100%;
}
.scalar-container {
height: 100vh;
width: 100vw;
}
/* 覆盖 VitePress 可能存在的样式干扰 */
.scalar-container :deep(.scalar-api-reference) {
min-height: 100vh;
}
</style>
+3780 -57
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -8,5 +8,8 @@
},
"devDependencies": {
"vitepress": "^1.6.4"
},
"dependencies": {
"@scalar/api-reference": "^1.48.2"
}
}
-101
View File
@@ -1,101 +0,0 @@
package router
import (
"encoding/json"
"net/http"
"strings"
"github.com/engigu/baihu-panel/internal/constant"
"github.com/engigu/baihu-panel/internal/middleware"
"github.com/engigu/baihu-panel/internal/models/vo"
"github.com/engigu/baihu-panel/internal/services"
"github.com/engigu/baihu-panel/openapi_docs"
"github.com/gin-gonic/gin"
)
func initOpenAPIRoutes(root *gin.RouterGroup, urlPrefix string) {
// OpenAPI documentation using Scalar UI (带 Basic Auth 认证)
root.GET("/openapi/*any", func(c *gin.Context) {
// 禁用整个 OpenAPI 路由的缓存
c.Header("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate")
c.Header("Pragma", "no-cache")
c.Header("Expires", "0")
settingsSvc := services.NewSettingsService()
siteConfig := settingsSvc.GetSection(constant.SectionSite)
tokenJson := siteConfig[constant.KeyOpenapiToken]
enabled := false
if tokenJson != "" {
var tokenConfig vo.TokenConfig
if err := json.Unmarshal([]byte(tokenJson), &tokenConfig); err == nil {
enabled = tokenConfig.Enabled
}
}
// 如果未开启文档,直接返回 404 SPA 页面
if !enabled {
serveSPA(c, urlPrefix, 404)
return
}
// 执行主站 Cookie 认证
middleware.AuthRequired()(c)
if c.IsAborted() {
return
}
// 获取内部路径并标准化(移除前后的所有斜杠)
path := strings.Trim(c.Param("any"), "/")
// 1. 根路径或空路径 -> 重定向到 index.html
if path == "" {
c.Redirect(http.StatusMovedPermanently, c.Request.URL.Path+"index.html")
return
}
// 2. 提供 Scalar 渲染的 HTML 页面
if path == "index.html" {
scalarHTML := `<!doctype html>
<html>
<head>
<title>Baihu Panel API Reference</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
body { margin: 0; }
</style>
</head>
<body>
<script id="api-reference" data-url="` + urlPrefix + `/openapi/doc.json"></script>
<script src="https://cdn.jsdelivr.net/npm/@scalar/api-reference"></script>
</body>
</html>`
c.Header("Content-Type", "text/html; charset=utf-8")
c.Status(http.StatusOK)
c.Writer.Write([]byte(scalarHTML))
c.Abort()
return
}
// 3. 提供给 Scalar/Swagger 使用 host 环境变量后的 doc.json 内容
if path == "doc.json" {
// 动态设置当前请求的域名作为 Swagger Host
openapi_docs.SwaggerInfo.Host = c.Request.Host
scheme := "http"
if c.Request.TLS != nil || c.Request.Header.Get("X-Forwarded-Proto") == "https" {
scheme = "https"
}
openapi_docs.SwaggerInfo.Schemes = []string{scheme}
doc := openapi_docs.SwaggerInfo.ReadDoc()
c.Header("Content-Type", "application/json; charset=utf-8")
c.String(http.StatusOK, doc)
return
}
// 其他未匹配路径 -> 返回 404 SPA 页面
serveSPA(c, urlPrefix, 404)
})
}
-3
View File
@@ -59,9 +59,6 @@ func Setup(c *Controllers) *gin.Engine {
// 1. [ location /assets ] 静态资源路由
initStaticRoutes(root)
// 2. [ location /openapi ] OpenAPI 文档路由
initOpenAPIRoutes(root, urlPrefix)
// 3. [ location /api ] 内部 API 路由组
apiV1 := root.Group("/api/v1")
initPublicAPIRoutes(apiV1, c) // 公开接口 (无需认证)
-1
View File
@@ -7,7 +7,6 @@ import (
"github.com/engigu/baihu-panel/cmd"
"github.com/engigu/baihu-panel/internal/bootstrap"
"github.com/engigu/baihu-panel/internal/constant"
_ "github.com/engigu/baihu-panel/openapi_docs" // This will be generated by swag init
)
// @title Baihu Panel API
-1043
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-615
View File
@@ -1,615 +0,0 @@
basePath: /open2api/v1
definitions:
github_com_engigu_baihu-panel_internal_utils.Response:
properties:
code:
type: integer
data: {}
msg:
type: string
type: object
utils.PaginationData:
properties:
data: {}
page:
type: integer
page_size:
type: integer
total:
type: integer
type: object
vo.EnvVO:
properties:
created_at:
type: string
hidden:
type: boolean
id:
type: string
name:
type: string
remark:
type: string
updated_at:
type: string
value:
type: string
type: object
vo.ExecutionResultVO:
properties:
duration:
type: integer
end_time:
type: string
error:
type: string
exit_code:
type: integer
log_id:
type: string
output:
type: string
start_time:
type: string
status:
type: string
success:
type: boolean
task_id:
type: string
type: object
vo.TaskLogVO:
properties:
agent_id:
type: string
command:
type: string
created_at:
type: string
duration:
type: integer
end_time:
type: string
error:
type: string
exit_code:
type: integer
id:
type: string
output:
type: string
start_time:
type: string
status:
type: string
task_id:
type: string
task_name:
type: string
task_type:
type: string
type: object
vo.TaskVO:
properties:
agent_id:
type: string
clean_config:
type: string
command:
type: string
config:
type: string
created_at:
type: string
enabled:
type: boolean
envs:
type: string
id:
type: string
languages:
items:
additionalProperties:
type: string
type: object
type: array
last_run:
type: string
name:
type: string
next_run:
type: string
random_range:
type: integer
retry_count:
type: integer
retry_interval:
type: integer
schedule:
type: string
tags:
type: string
timeout:
type: integer
trigger_type:
type: string
type:
type: string
updated_at:
type: string
work_dir:
type: string
type: object
host: localhost:8052
info:
contact:
email: support@swagger.io
name: API Support
url: http://www.swagger.io/support
description: Baihu Panel OpenAPI Server documentation.
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
termsOfService: http://swagger.io/terms/
title: Baihu Panel API
version: "1.0"
paths:
/env:
get:
consumes:
- application/json
description: 分页获取环境变量列表,支持按名称筛选
parameters:
- description: 按名称模糊查询
in: query
name: name
type: string
- description: 页码
in: query
name: page
type: integer
- description: 每页数量
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
allOf:
- $ref: '#/definitions/utils.PaginationData'
- properties:
data:
items:
$ref: '#/definitions/vo.EnvVO'
type: array
type: object
type: object
security:
- BearerAuth: []
summary: 获取环境变量列表
tags:
- 环境变量
/env/{id}:
get:
consumes:
- application/json
description: 根据 ID 获取环境变量详情
parameters:
- description: 环境变量ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
$ref: '#/definitions/vo.EnvVO'
type: object
"404":
description: Not Found
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 获取环境变量详情
tags:
- 环境变量
/env/{id}/tasks:
get:
consumes:
- application/json
description: 获取引用了该环境变量的任务列表
parameters:
- description: 环境变量ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
items:
$ref: '#/definitions/vo.TaskVO'
type: array
type: object
security:
- BearerAuth: []
summary: 获取关联任务
tags:
- 环境变量
/env/all:
get:
consumes:
- application/json
description: 获取当前用户的所有环境变量(不分页)
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
items:
$ref: '#/definitions/vo.EnvVO'
type: array
type: object
security:
- BearerAuth: []
summary: 获取所有环境变量
tags:
- 环境变量
/execute/results:
get:
consumes:
- application/json
description: 获取最新任务或命令执行的结果列表
parameters:
- description: 数量 (默认 10)
in: query
name: count
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
items:
$ref: '#/definitions/vo.ExecutionResultVO'
type: array
type: object
security:
- BearerAuth: []
summary: 获取最新执行结果
tags:
- 任务执行
/execute/task/{id}:
post:
consumes:
- application/json
description: 立即执行指定的任务
parameters:
- description: 任务ID
in: path
name: id
required: true
type: string
- description: '执行参数 (envs: 环境变量字典)'
in: body
name: body
schema:
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
$ref: '#/definitions/vo.ExecutionResultVO'
type: object
"400":
description: Bad Request
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 运行任务
tags:
- 任务执行
/logs:
get:
consumes:
- application/json
description: 分页获取任务日志列表,支持按任务 ID、任务名称、状态筛选
parameters:
- description: 任务 ID
in: query
name: task_id
type: string
- description: 任务名称
in: query
name: task_name
type: string
- description: 状态
in: query
name: status
type: string
- description: 页码
in: query
name: page
type: integer
- description: 每页数量
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
allOf:
- $ref: '#/definitions/utils.PaginationData'
- properties:
data:
items:
$ref: '#/definitions/vo.TaskLogVO'
type: array
type: object
type: object
security:
- BearerAuth: []
summary: 获取任务日志列表
tags:
- 日志管理
/logs/{id}:
get:
consumes:
- application/json
description: 根据 ID 获取任务日志详细内容(包含输出)
parameters:
- description: 日志ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
$ref: '#/definitions/vo.TaskLogVO'
type: object
"404":
description: Not Found
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 获取日志详情
tags:
- 日志管理
/tasks:
get:
consumes:
- application/json
description: 分页获取任务列表,支持按名称、Agent ID、标签、类型筛选
parameters:
- description: 任务名称
in: query
name: name
type: string
- description: Agent ID
in: query
name: agent_id
type: string
- description: 标签
in: query
name: tags
type: string
- description: 任务类型
in: query
name: type
type: string
- description: 页码
in: query
name: page
type: integer
- description: 每页数量
in: query
name: page_size
type: integer
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
allOf:
- $ref: '#/definitions/utils.PaginationData'
- properties:
data:
items:
$ref: '#/definitions/vo.TaskVO'
type: array
type: object
type: object
security:
- BearerAuth: []
summary: 获取任务列表
tags:
- 任务管理
/tasks/{id}:
delete:
consumes:
- application/json
description: 根据 ID 删除任务
parameters:
- description: 任务ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
"404":
description: Not Found
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 删除任务
tags:
- 任务管理
get:
consumes:
- application/json
description: 根据 ID 获取任务详情
parameters:
- description: 任务ID
in: path
name: id
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
$ref: '#/definitions/vo.TaskVO'
type: object
"404":
description: Not Found
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 获取任务详情
tags:
- 任务管理
put:
consumes:
- application/json
description: 根据 ID 更新任务信息
parameters:
- description: 任务ID
in: path
name: id
required: true
type: string
- description: 任务更新信息
in: body
name: body
required: true
schema:
type: object
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
- properties:
data:
$ref: '#/definitions/vo.TaskVO'
type: object
"404":
description: Not Found
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 更新任务
tags:
- 任务管理
/tasks/stop/{logID}:
post:
consumes:
- application/json
description: 根据运行日志 ID 停止正在执行的任务
parameters:
- description: 运行日志ID
in: path
name: logID
required: true
type: string
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
"400":
description: Bad Request
schema:
$ref: '#/definitions/github_com_engigu_baihu-panel_internal_utils.Response'
security:
- BearerAuth: []
summary: 停止任务
tags:
- 任务管理
securityDefinitions:
BearerAuth:
description: Type "Bearer" followed by a space and the API token.
in: header
name: Authorization
type: apiKey
swagger: "2.0"
+5 -9
View File
@@ -22,8 +22,6 @@ import {
const { refreshSettings } = useSiteSettings()
const baseUrl = (window as any).__BASE_URL__ || ''
const form = ref<SiteSettings>({
title: '',
subtitle: '',
@@ -113,11 +111,7 @@ async function copyOpenapiToken() {
}
function openSwaggerDocs() {
if (!form.value.openapi_enabled) {
toast.error('必须先开启 OpenAPI 才能查看接口文档页面')
return
}
window.open(`${baseUrl}/openapi/index.html`, '_blank')
window.open('https://engigu.github.io/baihu-panel/guide/api.html', '_blank')
}
@@ -245,7 +239,8 @@ onMounted(loadSettings)
<div class="flex items-center gap-2">
<h3 class="text-lg font-medium text-foreground whitespace-nowrap">OpenAPI Token</h3>
<Badge variant="secondary"
class="font-normal text-xs bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20 whitespace-nowrap">推荐方式</Badge>
class="font-normal text-xs bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20 whitespace-nowrap">
推荐方式</Badge>
</div>
<div class="flex items-center justify-between sm:justify-end w-full sm:w-auto gap-4">
<a href="#" @click.prevent="openSwaggerDocs"
@@ -261,7 +256,8 @@ onMounted(loadSettings)
</div>
<p class="text-sm text-muted-foreground mb-4">开启全局 OpenAPI 直接访问能力配置后可通过请求头 <code
class="bg-muted px-1.5 py-0.5 rounded text-xs select-all font-sans">Authorization: Bearer &lt;在此生成的Token&gt;</code>
以第三方身份调用系统的所有接口请妥善保管 Token 并设置合理的有效期<span class="text-amber-600 dark:text-amber-500 font-medium ml-1">注意必须先开启本功能才能查看接口文档页面和对接调用</span></p>
以第三方身份调用系统的所有接口请妥善保管 Token 并设置合理的有效期<span
class="text-amber-600 dark:text-amber-500 font-medium ml-1">注意必须先开启本功能才能查看接口文档页面和对接调用</span></p>
<div class="grid grid-cols-1 sm:grid-cols-4 items-center gap-2 sm:gap-4 mb-4">
<Label class="sm:text-right text-muted-foreground">Token 密钥</Label>