feat: adjust openapi page laod
This commit is contained in:
@@ -62,7 +62,7 @@ func (ec *EnvController) CreateEnvVar(c *gin.Context) {
|
|||||||
// @Param name query string false "按名称模糊查询"
|
// @Param name query string false "按名称模糊查询"
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "每页数量"
|
// @Param page_size query int false "每页数量"
|
||||||
// @Success 200 {object} utils.Response{data=utils.PaginationData{list=[]vo.EnvVO}}
|
// @Success 200 {object} utils.Response{data=utils.PaginationData{data=[]vo.EnvVO}}
|
||||||
// @Router /env [get]
|
// @Router /env [get]
|
||||||
func (ec *EnvController) GetEnvVars(c *gin.Context) {
|
func (ec *EnvController) GetEnvVars(c *gin.Context) {
|
||||||
userID := c.GetString("userID")
|
userID := c.GetString("userID")
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ func NewLogController() *LogController {
|
|||||||
// @Param status query string false "状态"
|
// @Param status query string false "状态"
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "每页数量"
|
// @Param page_size query int false "每页数量"
|
||||||
// @Success 200 {object} utils.Response{data=utils.PaginationData{list=[]vo.TaskLogVO}}
|
// @Success 200 {object} utils.Response{data=utils.PaginationData{data=[]vo.TaskLogVO}}
|
||||||
// @Router /logs [get]
|
// @Router /logs [get]
|
||||||
func (lc *LogController) GetLogs(c *gin.Context) {
|
func (lc *LogController) GetLogs(c *gin.Context) {
|
||||||
p := utils.ParsePagination(c)
|
p := utils.ParsePagination(c)
|
||||||
|
|||||||
@@ -330,11 +330,11 @@ func (sc *SettingsController) GetLoginLogs(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
utils.Success(c, gin.H{
|
utils.Success(c, utils.PaginationData{
|
||||||
"data": vo.ToLoginLogVOListFromModels(logs),
|
Data: vo.ToLoginLogVOListFromModels(logs),
|
||||||
"total": total,
|
Total: total,
|
||||||
"page": page,
|
Page: page,
|
||||||
"page_size": pageSize,
|
PageSize: pageSize,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ func (tc *TaskController) CreateTask(c *gin.Context) {
|
|||||||
// @Param type query string false "任务类型"
|
// @Param type query string false "任务类型"
|
||||||
// @Param page query int false "页码"
|
// @Param page query int false "页码"
|
||||||
// @Param page_size query int false "每页数量"
|
// @Param page_size query int false "每页数量"
|
||||||
// @Success 200 {object} utils.Response{data=utils.PaginationData{list=[]vo.TaskVO}}
|
// @Success 200 {object} utils.Response{data=utils.PaginationData{data=[]vo.TaskVO}}
|
||||||
// @Router /tasks [get]
|
// @Router /tasks [get]
|
||||||
func (tc *TaskController) GetTasks(c *gin.Context) {
|
func (tc *TaskController) GetTasks(c *gin.Context) {
|
||||||
p := utils.ParsePagination(c)
|
p := utils.ParsePagination(c)
|
||||||
|
|||||||
+114
-77
@@ -69,8 +69,50 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
root = router.Group("")
|
root = router.Group("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initStaticRoutes(root)
|
||||||
|
initOpenAPIRoutes(root, urlPrefix)
|
||||||
|
|
||||||
|
// API 路由组
|
||||||
|
apiV1 := root.Group("/api/v1")
|
||||||
|
initPublicAPIRoutes(apiV1, c)
|
||||||
|
initAuthorizedAPIRoutes(apiV1, c)
|
||||||
|
initAgentAPIRoutes(root, c)
|
||||||
|
|
||||||
|
// SPA 兜底路由 - 返回 index.html(HTML禁用缓存以保证实时同步)
|
||||||
|
// 必须在最后注册,作为兜底路由
|
||||||
|
router.NoRoute(func(ctx *gin.Context) {
|
||||||
|
path := ctx.Request.URL.Path
|
||||||
|
|
||||||
|
// 如果配置了前缀,只处理带前缀的路径
|
||||||
|
if urlPrefix != "" && !strings.HasPrefix(path, urlPrefix) {
|
||||||
|
ctx.Status(404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析实际的相对路径
|
||||||
|
relPath := strings.TrimPrefix(path, urlPrefix)
|
||||||
|
if !strings.HasPrefix(relPath, "/") {
|
||||||
|
relPath = "/" + relPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// 拦截属于 API 或静态资源目录下不存在的请求,绝不能返回 index.html 造成前端 MIME 错误
|
||||||
|
if strings.HasPrefix(relPath, "/api/") || strings.HasPrefix(relPath, "/assets/") {
|
||||||
|
ctx.String(404, "Not Found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
serveSPA(ctx, urlPrefix, 200)
|
||||||
|
})
|
||||||
|
|
||||||
|
return router
|
||||||
|
}
|
||||||
|
|
||||||
|
func initStaticRoutes(root *gin.RouterGroup) {
|
||||||
staticFS := static.GetFS()
|
staticFS := static.GetFS()
|
||||||
if staticFS != nil {
|
if staticFS == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 静态资源服务(Vue SPA),带缓存头部
|
// 静态资源服务(Vue SPA),带缓存头部
|
||||||
assetsGroup := root.Group("/assets")
|
assetsGroup := root.Group("/assets")
|
||||||
assetsGroup.Use(cacheControl("public, max-age=31536000, immutable")) // 带哈希的资源缓存
|
assetsGroup.Use(cacheControl("public, max-age=31536000, immutable")) // 带哈希的资源缓存
|
||||||
@@ -86,8 +128,9 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
ctx.Header("Cache-Control", "public, max-age=86400") // 缓存1天
|
ctx.Header("Cache-Control", "public, max-age=86400") // 缓存1天
|
||||||
ctx.Data(200, "image/svg+xml", data)
|
ctx.Data(200, "image/svg+xml", data)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initOpenAPIRoutes(root *gin.RouterGroup, urlPrefix string) {
|
||||||
// OpenAPI documentation using Scalar UI (带 Basic Auth 认证)
|
// OpenAPI documentation using Scalar UI (带 Basic Auth 认证)
|
||||||
root.GET("/openapi/*any", func(c *gin.Context) {
|
root.GET("/openapi/*any", func(c *gin.Context) {
|
||||||
settingsSvc := services.NewSettingsService()
|
settingsSvc := services.NewSettingsService()
|
||||||
@@ -112,14 +155,13 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
middleware.SwaggerAuth()(c)
|
middleware.SwaggerAuth()(c)
|
||||||
if c.IsAborted() {
|
if c.IsAborted() {
|
||||||
// 如果认证失败(且被中间件置为 404,如密码错误且我们想要隐藏它)
|
// 如果认证失败(且被中间件置为 404,如密码错误且我们想要隐藏它)
|
||||||
if c.Writer.Status() == 404 {
|
if c.Writer.Status() == http.StatusNotFound {
|
||||||
serveSPA(c, urlPrefix, 404)
|
serveSPA(c, urlPrefix, 404)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取内部路径并标准化(移除前后的所有斜杠)
|
// 获取内部路径并标准化(移除前后的所有斜杠)
|
||||||
// c.Param("any") 对于 *any 匹配通常包含领先斜杠,如 "/index.html"
|
|
||||||
path := strings.Trim(c.Param("any"), "/")
|
path := strings.Trim(c.Param("any"), "/")
|
||||||
|
|
||||||
// 1. 根路径或空路径 -> 重定向到 index.html
|
// 1. 根路径或空路径 -> 重定向到 index.html
|
||||||
@@ -163,10 +205,9 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
// 其他未匹配路径 -> 返回 404 SPA 页面
|
// 其他未匹配路径 -> 返回 404 SPA 页面
|
||||||
serveSPA(c, urlPrefix, 404)
|
serveSPA(c, urlPrefix, 404)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// API 路由组
|
func initPublicAPIRoutes(api *gin.RouterGroup, c *Controllers) {
|
||||||
api := root.Group("/api/v1")
|
|
||||||
{
|
|
||||||
// Health check (无需认证)
|
// Health check (无需认证)
|
||||||
api.GET("/ping", func(ctx *gin.Context) {
|
api.GET("/ping", func(ctx *gin.Context) {
|
||||||
ctx.JSON(200, gin.H{"message": "pong"})
|
ctx.JSON(200, gin.H{"message": "pong"})
|
||||||
@@ -182,8 +223,9 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
|
|
||||||
// 公开的站点设置(无需认证)
|
// 公开的站点设置(无需认证)
|
||||||
api.GET("/settings/public", c.Settings.GetPublicSiteSettings)
|
api.GET("/settings/public", c.Settings.GetPublicSiteSettings)
|
||||||
|
}
|
||||||
|
|
||||||
// 需要认证的路由
|
func initAuthorizedAPIRoutes(api *gin.RouterGroup, c *Controllers) {
|
||||||
authorized := api.Group("")
|
authorized := api.Group("")
|
||||||
authorized.Use(middleware.AuthRequired())
|
authorized.Use(middleware.AuthRequired())
|
||||||
{
|
{
|
||||||
@@ -196,8 +238,29 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
authorized.GET("/sendstats", c.Dashboard.GetSendStats)
|
authorized.GET("/sendstats", c.Dashboard.GetSendStats)
|
||||||
authorized.GET("/taskstats", c.Dashboard.GetTaskStats)
|
authorized.GET("/taskstats", c.Dashboard.GetTaskStats)
|
||||||
|
|
||||||
// 任务模块
|
registerTaskRoutes(authorized, c)
|
||||||
tasks := authorized.Group("/tasks")
|
registerEnvRoutes(authorized, c)
|
||||||
|
registerScriptRoutes(authorized, c)
|
||||||
|
registerFileRoutes(authorized, c)
|
||||||
|
registerLogRoutes(authorized, c)
|
||||||
|
registerTerminalRoutes(authorized, c)
|
||||||
|
registerSettingsRoutes(authorized, c)
|
||||||
|
registerDependencyRoutes(authorized, c)
|
||||||
|
registerAgentRoutes(authorized, c)
|
||||||
|
registerMiseRoutes(authorized, c)
|
||||||
|
registerNotificationRoutes(authorized, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通知发送 API(使用通知 Token 认证,供脚本调用)
|
||||||
|
notifyAPI := api.Group("/notify")
|
||||||
|
notifyAPI.Use(middleware.NotifyTokenAuth())
|
||||||
|
{
|
||||||
|
notifyAPI.POST("/send", c.Notification.SendNotification)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerTaskRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
|
tasks := g.Group("/tasks")
|
||||||
{
|
{
|
||||||
tasks.POST("", c.Task.CreateTask)
|
tasks.POST("", c.Task.CreateTask)
|
||||||
tasks.GET("", c.Task.GetTasks)
|
tasks.GET("", c.Task.GetTasks)
|
||||||
@@ -207,16 +270,16 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
tasks.POST("/stop/:logID", c.Task.StopTask)
|
tasks.POST("/stop/:logID", c.Task.StopTask)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 任务执行模块
|
execution := g.Group("/execute")
|
||||||
execution := authorized.Group("/execute")
|
|
||||||
{
|
{
|
||||||
execution.POST("/task/:id", c.Executor.ExecuteTask)
|
execution.POST("/task/:id", c.Executor.ExecuteTask)
|
||||||
execution.POST("/command", c.Executor.ExecuteCommand)
|
execution.POST("/command", c.Executor.ExecuteCommand)
|
||||||
execution.GET("/results", c.Executor.GetLastResults)
|
execution.GET("/results", c.Executor.GetLastResults)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 环境变量模块
|
func registerEnvRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
env := authorized.Group("/env")
|
env := g.Group("/env")
|
||||||
{
|
{
|
||||||
env.POST("", c.Env.CreateEnvVar)
|
env.POST("", c.Env.CreateEnvVar)
|
||||||
env.GET("", c.Env.GetEnvVars)
|
env.GET("", c.Env.GetEnvVars)
|
||||||
@@ -226,9 +289,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
env.PUT("/:id", c.Env.UpdateEnvVar)
|
env.PUT("/:id", c.Env.UpdateEnvVar)
|
||||||
env.DELETE("/:id", c.Env.DeleteEnvVar)
|
env.DELETE("/:id", c.Env.DeleteEnvVar)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 脚本模块
|
func registerScriptRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
scripts := authorized.Group("/scripts")
|
scripts := g.Group("/scripts")
|
||||||
{
|
{
|
||||||
scripts.POST("", c.Script.CreateScript)
|
scripts.POST("", c.Script.CreateScript)
|
||||||
scripts.GET("", c.Script.GetScripts)
|
scripts.GET("", c.Script.GetScripts)
|
||||||
@@ -236,9 +300,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
scripts.PUT("/:id", c.Script.UpdateScript)
|
scripts.PUT("/:id", c.Script.UpdateScript)
|
||||||
scripts.DELETE("/:id", c.Script.DeleteScript)
|
scripts.DELETE("/:id", c.Script.DeleteScript)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 文件管理模块
|
func registerFileRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
files := authorized.Group("/files")
|
files := g.Group("/files")
|
||||||
{
|
{
|
||||||
files.GET("/tree", c.File.GetFileTree)
|
files.GET("/tree", c.File.GetFileTree)
|
||||||
files.GET("/content", c.File.GetFileContent)
|
files.GET("/content", c.File.GetFileContent)
|
||||||
@@ -252,9 +317,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
files.POST("/upload", c.File.UploadArchive)
|
files.POST("/upload", c.File.UploadArchive)
|
||||||
files.POST("/uploadfiles", c.File.UploadFiles)
|
files.POST("/uploadfiles", c.File.UploadFiles)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 日志查看模块
|
func registerLogRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
logs := authorized.Group("/logs")
|
logs := g.Group("/logs")
|
||||||
{
|
{
|
||||||
logs.GET("", c.Log.GetLogs)
|
logs.GET("", c.Log.GetLogs)
|
||||||
logs.POST("/clear", c.Log.ClearLogs)
|
logs.POST("/clear", c.Log.ClearLogs)
|
||||||
@@ -262,14 +328,16 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
logs.GET("/:id", c.Log.GetLogDetail)
|
logs.GET("/:id", c.Log.GetLogDetail)
|
||||||
logs.DELETE("/:id", c.Log.DeleteLog)
|
logs.DELETE("/:id", c.Log.DeleteLog)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 终端模块
|
func registerTerminalRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
authorized.GET("/terminal/ws", c.Terminal.HandleWebSocket)
|
g.GET("/terminal/ws", c.Terminal.HandleWebSocket)
|
||||||
authorized.POST("/terminal/exec", c.Terminal.ExecuteShellCommand)
|
g.POST("/terminal/exec", c.Terminal.ExecuteShellCommand)
|
||||||
authorized.GET("/terminal/cmds", c.Terminal.GetCommands)
|
g.GET("/terminal/cmds", c.Terminal.GetCommands)
|
||||||
|
}
|
||||||
|
|
||||||
// 设置中心模块
|
func registerSettingsRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
settings := authorized.Group("/settings")
|
settings := g.Group("/settings")
|
||||||
{
|
{
|
||||||
settings.POST("/password", c.Settings.ChangePassword)
|
settings.POST("/password", c.Settings.ChangePassword)
|
||||||
settings.GET("/site", c.Settings.GetSiteSettings)
|
settings.GET("/site", c.Settings.GetSiteSettings)
|
||||||
@@ -289,9 +357,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
settings.GET("/:section/:key", c.Settings.GetSetting)
|
settings.GET("/:section/:key", c.Settings.GetSetting)
|
||||||
settings.POST("/:section/:key/generate", c.Settings.GenerateSettingToken)
|
settings.POST("/:section/:key/generate", c.Settings.GenerateSettingToken)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Dependency routes (依赖管理)
|
func registerDependencyRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
deps := authorized.Group("/deps")
|
deps := g.Group("/deps")
|
||||||
{
|
{
|
||||||
deps.GET("", c.Dependency.List)
|
deps.GET("", c.Dependency.List)
|
||||||
deps.POST("", c.Dependency.Create)
|
deps.POST("", c.Dependency.Create)
|
||||||
@@ -304,9 +373,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
deps.POST("/reinstall-all-cmd", c.Dependency.GetReinstallAllCommand)
|
deps.POST("/reinstall-all-cmd", c.Dependency.GetReinstallAllCommand)
|
||||||
deps.GET("/installed", c.Dependency.GetInstalled)
|
deps.GET("/installed", c.Dependency.GetInstalled)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Agent routes (Agent 管理)
|
func registerAgentRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
agents := authorized.Group("/agents")
|
agents := g.Group("/agents")
|
||||||
{
|
{
|
||||||
agents.GET("", c.Agent.List)
|
agents.GET("", c.Agent.List)
|
||||||
agents.GET("/version", c.Agent.GetVersion)
|
agents.GET("/version", c.Agent.GetVersion)
|
||||||
@@ -320,8 +390,15 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
agents.DELETE("/tokens/:id", c.Agent.DeleteToken)
|
agents.DELETE("/tokens/:id", c.Agent.DeleteToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mise routes (Mise 管理)
|
// Agent API(供前端调用,保持在 v1 下)
|
||||||
mise := authorized.Group("/mise")
|
agentAPIv1 := g.Group("/agent")
|
||||||
|
{
|
||||||
|
agentAPIv1.GET("/download", c.Agent.Download)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerMiseRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
|
mise := g.Group("/mise")
|
||||||
{
|
{
|
||||||
mise.GET("/ls", c.Mise.List)
|
mise.GET("/ls", c.Mise.List)
|
||||||
mise.POST("/sync", c.Mise.Sync)
|
mise.POST("/sync", c.Mise.Sync)
|
||||||
@@ -329,15 +406,10 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
mise.GET("/versions", c.Mise.Versions)
|
mise.GET("/versions", c.Mise.Versions)
|
||||||
mise.GET("/verify-cmd", c.Mise.VerifyCommand)
|
mise.GET("/verify-cmd", c.Mise.VerifyCommand)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Agent API(供前端调用,保持在 v1 下)
|
func registerNotificationRoutes(g *gin.RouterGroup, c *Controllers) {
|
||||||
agentAPIv1 := authorized.Group("/agent")
|
notify := g.Group("/notify")
|
||||||
{
|
|
||||||
agentAPIv1.GET("/download", c.Agent.Download)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 通知推送模块
|
|
||||||
notify := authorized.Group("/notify")
|
|
||||||
{
|
{
|
||||||
notify.GET("/types", c.Notification.GetChannelTypes)
|
notify.GET("/types", c.Notification.GetChannelTypes)
|
||||||
notify.GET("/channels", c.Notification.GetChannels)
|
notify.GET("/channels", c.Notification.GetChannels)
|
||||||
@@ -348,16 +420,9 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
notify.POST("/bindings", c.Notification.SaveBinding)
|
notify.POST("/bindings", c.Notification.SaveBinding)
|
||||||
notify.DELETE("/bindings/:id", c.Notification.DeleteBinding)
|
notify.DELETE("/bindings/:id", c.Notification.DeleteBinding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 通知发送 API(使用通知 Token 认证,供脚本调用)
|
|
||||||
notifyAPI := api.Group("/notify")
|
|
||||||
notifyAPI.Use(middleware.NotifyTokenAuth())
|
|
||||||
{
|
|
||||||
notifyAPI.POST("/send", c.Notification.SendNotification)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
func initAgentAPIRoutes(root *gin.RouterGroup, c *Controllers) {
|
||||||
// Agent API(供远程 Agent 调用,不使用 /v1 版本号)
|
// Agent API(供远程 Agent 调用,不使用 /v1 版本号)
|
||||||
agentAPI := root.Group("/api/agent")
|
agentAPI := root.Group("/api/agent")
|
||||||
{
|
{
|
||||||
@@ -367,34 +432,6 @@ func Setup(c *Controllers) *gin.Engine {
|
|||||||
agentAPI.GET("/download", c.Agent.Download) // 也在这里注册,兼容 Agent 调用
|
agentAPI.GET("/download", c.Agent.Download) // 也在这里注册,兼容 Agent 调用
|
||||||
agentAPI.GET("/ws", c.Agent.WSConnect) // WebSocket 连接
|
agentAPI.GET("/ws", c.Agent.WSConnect) // WebSocket 连接
|
||||||
}
|
}
|
||||||
|
|
||||||
// SPA 兜底路由 - 返回 index.html(HTML禁用缓存以保证实时同步)
|
|
||||||
// 必须在最后注册,作为兜底路由
|
|
||||||
router.NoRoute(func(ctx *gin.Context) {
|
|
||||||
path := ctx.Request.URL.Path
|
|
||||||
|
|
||||||
// 如果配置了前缀,只处理带前缀的路径
|
|
||||||
if urlPrefix != "" && !strings.HasPrefix(path, urlPrefix) {
|
|
||||||
ctx.Status(404)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 解析实际的相对路径
|
|
||||||
relPath := strings.TrimPrefix(path, urlPrefix)
|
|
||||||
if !strings.HasPrefix(relPath, "/") {
|
|
||||||
relPath = "/" + relPath
|
|
||||||
}
|
|
||||||
|
|
||||||
// 拦截属于 API 或静态资源目录下不存在的请求,绝不能返回 index.html 造成前端 MIME 错误
|
|
||||||
if strings.HasPrefix(relPath, "/api/") || strings.HasPrefix(relPath, "/assets/") {
|
|
||||||
ctx.String(404, "Not Found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
serveSPA(ctx, urlPrefix, 200)
|
|
||||||
})
|
|
||||||
|
|
||||||
return router
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveSPA 注入配置并返回 index.html 给前端渲染
|
// serveSPA 注入配置并返回 index.html 给前端渲染
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ func (p Pagination) Offset() int {
|
|||||||
|
|
||||||
// PaginationData 分页数据
|
// PaginationData 分页数据
|
||||||
type PaginationData struct {
|
type PaginationData struct {
|
||||||
List interface{} `json:"list"`
|
Data interface{} `json:"data"`
|
||||||
Total int64 `json:"total"`
|
Total int64 `json:"total"`
|
||||||
Page int `json:"page"`
|
Page int `json:"page"`
|
||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
@@ -62,7 +62,7 @@ type PaginationData struct {
|
|||||||
// PaginatedResponse 分页响应
|
// PaginatedResponse 分页响应
|
||||||
func PaginatedResponse(c *gin.Context, data interface{}, total int64, p Pagination) {
|
func PaginatedResponse(c *gin.Context, data interface{}, total int64, p Pagination) {
|
||||||
Success(c, PaginationData{
|
Success(c, PaginationData{
|
||||||
List: data,
|
Data: data,
|
||||||
Total: total,
|
Total: total,
|
||||||
Page: p.Page,
|
Page: p.Page,
|
||||||
PageSize: p.PageSize,
|
PageSize: p.PageSize,
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ export interface ExecutionResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskListResponse {
|
export interface TaskListResponse {
|
||||||
list: Task[]
|
data: Task[]
|
||||||
total: number
|
total: number
|
||||||
page: number
|
page: number
|
||||||
page_size: number
|
page_size: number
|
||||||
@@ -365,7 +365,7 @@ export interface EnvVar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvListResponse {
|
export interface EnvListResponse {
|
||||||
list: EnvVar[]
|
data: EnvVar[]
|
||||||
total: number
|
total: number
|
||||||
page: number
|
page: number
|
||||||
page_size: number
|
page_size: number
|
||||||
@@ -396,7 +396,7 @@ export interface TaskLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LogListResponse {
|
export interface LogListResponse {
|
||||||
list: TaskLog[]
|
data: TaskLog[]
|
||||||
total: number
|
total: number
|
||||||
page: number
|
page: number
|
||||||
page_size: number
|
page_size: number
|
||||||
@@ -457,7 +457,7 @@ export interface LoginLog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoginLogListResponse {
|
export interface LoginLogListResponse {
|
||||||
list: LoginLog[]
|
data: LoginLog[]
|
||||||
total: number
|
total: number
|
||||||
page: number
|
page: number
|
||||||
page_size: number
|
page_size: number
|
||||||
|
|||||||
@@ -34,10 +34,10 @@ let searchTimer: ReturnType<typeof setTimeout> | null = null
|
|||||||
async function loadEnvVars() {
|
async function loadEnvVars() {
|
||||||
try {
|
try {
|
||||||
const res = await api.env.list({ page: currentPage.value, page_size: pageSize.value, name: filterName.value || undefined })
|
const res = await api.env.list({ page: currentPage.value, page_size: pageSize.value, name: filterName.value || undefined })
|
||||||
envVars.value = res.list
|
envVars.value = res.data
|
||||||
total.value = res.total
|
total.value = res.total
|
||||||
// 初始化显示状态,根据数据库的 hidden 状态同步显示
|
// 初始化显示状态,根据数据库的 hidden 状态同步显示
|
||||||
res.list.forEach(env => {
|
res.data.forEach(env => {
|
||||||
showValues.value[env.id] = !env.hidden
|
showValues.value[env.id] = !env.hidden
|
||||||
})
|
})
|
||||||
} catch { toast.error('加载环境变量失败') }
|
} catch { toast.error('加载环境变量失败') }
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ async function loadLogs() {
|
|||||||
params.status = filterStatus.value
|
params.status = filterStatus.value
|
||||||
}
|
}
|
||||||
const response = await api.logs.list(params)
|
const response = await api.logs.list(params)
|
||||||
logs.value = response.list
|
logs.value = response.data
|
||||||
total.value = response.total
|
total.value = response.total
|
||||||
} catch {
|
} catch {
|
||||||
toast.error('加载日志失败')
|
toast.error('加载日志失败')
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ async function loadLogs() {
|
|||||||
page_size: pageSize.value,
|
page_size: pageSize.value,
|
||||||
username: filterUsername.value || undefined
|
username: filterUsername.value || undefined
|
||||||
})
|
})
|
||||||
logs.value = res.list
|
logs.value = res.data
|
||||||
total.value = res.total
|
total.value = res.total
|
||||||
} catch {
|
} catch {
|
||||||
toast.error('加载登录日志失败')
|
toast.error('加载登录日志失败')
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ async function loadTasks() {
|
|||||||
type: filterType.value === 'all' ? undefined : filterType.value,
|
type: filterType.value === 'all' ? undefined : filterType.value,
|
||||||
agent_id: filterAgentId.value || undefined
|
agent_id: filterAgentId.value || undefined
|
||||||
})
|
})
|
||||||
tasks.value = res.list
|
tasks.value = res.data
|
||||||
total.value = res.total
|
total.value = res.total
|
||||||
} catch { toast.error('加载任务失败') }
|
} catch { toast.error('加载任务失败') }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user