- SEO: 添加meta description/keywords/Open Graph/结构化数据/地理信息 - GEO: 添加geo.region/geo.position/ICBM等地理标记 - 手机端完全重写响应式: 咨询表单/导航卡片/hero区/标签全部适配 - 新增App候选码板块: 后台管理+导航页动态展示(支持录屏视频/下载链接) - 新增业务系统板块: 进销存/OA/财务/工单等,支持按年/按月/定制定价 - 后台新增App候选码管理页面(增删改查+上下架) - 后台新增业务系统管理页面(增删改查+上下架) - 导航页设置新增新板块标题配置 - 公开API: GET /api/v1/showcase/apps + /api/v1/showcase/systems
250 lines
7.3 KiB
Go
250 lines
7.3 KiB
Go
package router
|
||
|
||
import (
|
||
"net/http"
|
||
"time"
|
||
|
||
"gotest/internal/config"
|
||
"gotest/internal/database"
|
||
"gotest/internal/geoip"
|
||
"gotest/internal/handler"
|
||
"gotest/internal/middleware"
|
||
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
// Setup 初始化路由和中间件,返回 Gin 引擎
|
||
func Setup(
|
||
cfg *config.Config,
|
||
db *database.DB,
|
||
authH *handler.AuthHandler,
|
||
userH *handler.UserHandler,
|
||
adminH *handler.AdminHandler,
|
||
uploadH *handler.UploadHandler,
|
||
enterpriseH *handler.EnterpriseHandler,
|
||
shopH *handler.ShopHandler,
|
||
foodH *handler.FoodHandler,
|
||
gameH *handler.GameHandler,
|
||
appH *handler.AppHandler,
|
||
musicH *handler.MusicHandler,
|
||
dashboardH *handler.DashboardHandler,
|
||
customerH *handler.CustomerHandler,
|
||
accessLogH *handler.AccessLogHandler,
|
||
configH *handler.ConfigHandler,
|
||
ipLocationService *geoip.Service,
|
||
showcaseH *handler.ShowcaseHandler,
|
||
) *gin.Engine {
|
||
if cfg.Env.Name == "prod" {
|
||
gin.SetMode(gin.ReleaseMode)
|
||
}
|
||
|
||
r := gin.New()
|
||
|
||
// 全局中间件链(顺序:RequestID → Recover → Logger → CORS → RateLimit → AccessLog)
|
||
r.Use(middleware.RequestID())
|
||
r.Use(middleware.Recover())
|
||
r.Use(middleware.Logger())
|
||
r.Use(middleware.CORS(&cfg.CORS))
|
||
r.Use(middleware.RateLimit(&cfg.RateLimit))
|
||
r.Use(middleware.AccessLog(db.DB, ipLocationService))
|
||
|
||
// 健康检查(含数据库就绪探针)
|
||
r.GET("/api/health", func(c *gin.Context) {
|
||
dbStatus := "up"
|
||
if err := db.HealthCheck(); err != nil {
|
||
dbStatus = "down: " + err.Error()
|
||
}
|
||
status := http.StatusOK
|
||
if dbStatus != "up" {
|
||
status = http.StatusServiceUnavailable
|
||
}
|
||
c.JSON(status, gin.H{
|
||
"code": 0,
|
||
"message": "ok",
|
||
"data": gin.H{
|
||
"status": dbStatus,
|
||
"time": time.Now().Format(time.RFC3339),
|
||
"env": cfg.Env.Name,
|
||
"database": cfg.Database.Driver,
|
||
},
|
||
})
|
||
})
|
||
|
||
// 静态文件服务:上传的文件可通过 /uploads/* 访问
|
||
r.Static("/uploads", cfg.Upload.Path)
|
||
|
||
// API v1 路由组
|
||
api := r.Group("/api/v1")
|
||
{
|
||
// 认证(公开)
|
||
auth := api.Group("/auth")
|
||
{
|
||
auth.POST("/login", authH.Login)
|
||
}
|
||
|
||
// 管理员检查与初始化(公开)
|
||
adminPub := api.Group("/admin")
|
||
{
|
||
adminPub.GET("/check", adminH.CheckAdmin)
|
||
adminPub.POST("/init", adminH.InitAdmin)
|
||
}
|
||
|
||
// 企业数据 API(公开,3 套企业官网共用)
|
||
enterprise := api.Group("/enterprise")
|
||
{
|
||
enterprise.GET("/all", enterpriseH.GetAllData)
|
||
enterprise.GET("/company", enterpriseH.GetCompany)
|
||
enterprise.GET("/services", enterpriseH.ListServices)
|
||
enterprise.GET("/news", enterpriseH.ListNews)
|
||
enterprise.GET("/news/:id", enterpriseH.GetNews)
|
||
enterprise.GET("/team", enterpriseH.ListTeam)
|
||
}
|
||
|
||
// 电商数据 API(公开,跨境电商网站使用)
|
||
shop := api.Group("/shop")
|
||
{
|
||
shop.GET("/home", shopH.GetHomeData)
|
||
shop.GET("/categories", shopH.ListCategories)
|
||
shop.GET("/products", shopH.ListProducts)
|
||
shop.GET("/products/:id", shopH.GetProduct)
|
||
shop.GET("/featured", shopH.ListFeatured)
|
||
}
|
||
|
||
// 外卖数据 API(公开,3 套外卖网站共用)
|
||
food := api.Group("/food")
|
||
{
|
||
food.GET("/home", foodH.GetHomeData)
|
||
food.GET("/categories", foodH.ListCategories)
|
||
food.GET("/restaurants", foodH.ListRestaurants)
|
||
food.GET("/restaurants/:id", foodH.GetRestaurant)
|
||
food.GET("/restaurants/:id/menu", foodH.GetRestaurantMenu)
|
||
food.GET("/featured", foodH.ListFeatured)
|
||
}
|
||
|
||
// 游戏数据 API(公开,3 套游戏网站共用)
|
||
game := api.Group("/game")
|
||
{
|
||
game.GET("/home", gameH.GetHomeData)
|
||
game.GET("/categories", gameH.ListCategories)
|
||
game.GET("/games", gameH.ListGames)
|
||
game.GET("/games/:id", gameH.GetGame)
|
||
game.GET("/hot", gameH.ListHot)
|
||
game.GET("/new", gameH.ListNew)
|
||
}
|
||
|
||
// 应用数据 API(公开,3 套应用网站共用)
|
||
app := api.Group("/app")
|
||
{
|
||
app.GET("/home", appH.GetHomeData)
|
||
app.GET("/categories", appH.ListCategories)
|
||
app.GET("/apps", appH.ListApps)
|
||
app.GET("/apps/:id", appH.GetApp)
|
||
app.GET("/featured", appH.ListFeatured)
|
||
app.GET("/new", appH.ListNew)
|
||
}
|
||
|
||
// 音乐数据 API(公开,3 套音乐网站共用)
|
||
music := api.Group("/music")
|
||
{
|
||
music.GET("/home", musicH.GetHomeData)
|
||
music.GET("/categories", musicH.ListCategories)
|
||
music.GET("/songs", musicH.ListSongs)
|
||
music.GET("/songs/:id", musicH.GetSong)
|
||
music.GET("/hot", musicH.ListHot)
|
||
music.GET("/new", musicH.ListNew)
|
||
}
|
||
|
||
// 公开接口(无需认证)
|
||
// ...
|
||
|
||
// 客户信息收集(公开,无需认证)
|
||
customer := api.Group("/customer")
|
||
{
|
||
customer.POST("/submit", customerH.Submit)
|
||
}
|
||
|
||
// 导航页设置(公开,无需认证)
|
||
api.GET("/nav-settings", configH.GetNavSettings)
|
||
|
||
// App 候选码 & 业务系统(公开)
|
||
api.GET("/showcase/apps", showcaseH.ListAppShowcase)
|
||
api.GET("/showcase/systems", showcaseH.ListBizSystem)
|
||
|
||
// 需要登录的路由
|
||
authed := api.Group("")
|
||
authed.Use(middleware.JWTAuth(cfg.JWT.Secret))
|
||
{
|
||
// 用户资料
|
||
user := authed.Group("/user")
|
||
{
|
||
user.GET("/profile", userH.GetProfile)
|
||
user.PUT("/profile", userH.UpdateProfile)
|
||
user.PUT("/password", userH.ChangePassword)
|
||
}
|
||
// 文件上传(统一上传接口,支持按模块分类)
|
||
authed.POST("/upload", uploadH.Upload)
|
||
authed.GET("/upload/list", uploadH.ListFiles)
|
||
authed.GET("/upload/modules", uploadH.GetModules)
|
||
authed.DELETE("/upload", uploadH.DeleteFile)
|
||
}
|
||
|
||
// 管理端路由(需要登录 + admin 角色)
|
||
admin := api.Group("/admin")
|
||
admin.Use(middleware.JWTAuth(cfg.JWT.Secret), requireAdmin())
|
||
{
|
||
admin.GET("/users", userH.ListUsers)
|
||
admin.POST("/users", userH.CreateUser)
|
||
admin.PUT("/users/:id", userH.UpdateUser)
|
||
admin.DELETE("/users/:id", userH.DeleteUser)
|
||
|
||
// 仪表盘 & 内容管理(通用 CRUD)
|
||
admin.GET("/dashboard/stats", dashboardH.GetStats)
|
||
admin.GET("/dashboard/:table", dashboardH.ListItems)
|
||
admin.POST("/dashboard/:table", dashboardH.CreateItem)
|
||
admin.PUT("/dashboard/:table/:id", dashboardH.UpdateItem)
|
||
admin.DELETE("/dashboard/:table/:id", dashboardH.DeleteItem)
|
||
|
||
// 访问日志
|
||
admin.GET("/access-logs", accessLogH.ListLogs)
|
||
admin.GET("/access-logs/stats", accessLogH.GetStats)
|
||
admin.DELETE("/access-logs", accessLogH.DeleteLogs)
|
||
|
||
// 系统配置(webhook 等)
|
||
admin.GET("/config", configH.ListConfigs)
|
||
admin.GET("/config/:key", configH.GetConfig)
|
||
admin.PUT("/config/:key", configH.SetConfig)
|
||
admin.PUT("/config-batch", configH.BatchSetConfigs)
|
||
|
||
// Webhook 测试
|
||
admin.POST("/webhook/test", customerH.TestWebhook)
|
||
|
||
// App 候选码管理
|
||
admin.GET("/showcase/apps", showcaseH.AdminListAppShowcase)
|
||
admin.POST("/showcase/apps", showcaseH.CreateAppShowcase)
|
||
admin.PUT("/showcase/apps/:id", showcaseH.UpdateAppShowcase)
|
||
admin.DELETE("/showcase/apps/:id", showcaseH.DeleteAppShowcase)
|
||
|
||
// 业务系统管理
|
||
admin.GET("/showcase/systems", showcaseH.AdminListBizSystem)
|
||
admin.POST("/showcase/systems", showcaseH.CreateBizSystem)
|
||
admin.PUT("/showcase/systems/:id", showcaseH.UpdateBizSystem)
|
||
admin.DELETE("/showcase/systems/:id", showcaseH.DeleteBizSystem)
|
||
}
|
||
}
|
||
|
||
return r
|
||
}
|
||
|
||
// requireAdmin 管理员权限校验中间件
|
||
func requireAdmin() gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
if middleware.GetRole(c) != "admin" {
|
||
c.AbortWithStatusJSON(http.StatusForbidden, gin.H{
|
||
"code": 1, "message": "权限不足", "data": nil,
|
||
})
|
||
return
|
||
}
|
||
c.Next()
|
||
}
|
||
}
|