Files
trade/web/backend/internal/router/router.go
2026-05-07 22:29:00 +08:00

71 lines
1.7 KiB
Go

package router
import (
"io/fs"
"net/http"
"strings"
"github.com/go-chi/chi/v5"
"trade/web/internal/handlers"
mw "trade/web/internal/middleware"
)
func New(d *handlers.Deps, dist fs.FS) http.Handler {
r := chi.NewRouter()
r.Use(mw.Recover)
r.Use(mw.Logger)
r.Route("/api", func(r chi.Router) {
r.Post("/login", d.Login)
r.Group(func(r chi.Router) {
r.Use(mw.RequireUser)
r.Post("/logout", d.Logout)
r.Get("/me", d.Me)
r.Post("/change-password", d.ChangePassword)
r.Get("/scores", d.ListScores)
r.Get("/scores/{id}", d.GetScore)
r.Get("/contracts", d.ListContracts)
r.Get("/contracts/active", d.GetActiveContract)
r.Get("/candles", d.ListCandles)
r.Post("/run", d.RunPipeline)
r.Post("/run/batch", d.RunBatch)
r.Post("/run/range", d.RunRange)
r.Post("/run/full", d.RunFull)
r.Group(func(r chi.Router) {
r.Use(mw.RequireAdmin)
r.Get("/admin/users", d.AdminListUsers)
r.Post("/admin/users", d.AdminCreateUser)
r.Patch("/admin/users/{id}", d.AdminPatchUser)
r.Delete("/admin/users/{id}", d.AdminDeleteUser)
r.Post("/admin/reset-data", d.AdminResetData)
})
})
})
r.Handle("/*", spa(dist))
return r
}
// spa 返回单文件 SPA handler:文件存在则发文件,否则发 index.html。
func spa(root fs.FS) http.Handler {
fileServer := http.FileServer(http.FS(root))
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
path := strings.TrimPrefix(r.URL.Path, "/")
if path == "" {
path = "index.html"
}
if _, err := fs.Stat(root, path); err != nil {
// 找不到文件 → SPA 路由,回 index.html 让前端 router 处理
r2 := r.Clone(r.Context())
r2.URL.Path = "/"
fileServer.ServeHTTP(w, r2)
return
}
fileServer.ServeHTTP(w, r)
})
}