Files
opsx-licence/backend/router/router.go
T
Logan.LiandCursor 8cc2c83f9d feat: 通用授权后台、离线证、Waffo 支付页与仪表盘加强
支持多产品计划展示、LICOFF 离线签发、支付独立配置与调试,以及分析看板;同步更新 README 与集成文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-12 20:25:46 +08:00

247 lines
9.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package router
import (
"backend/config"
"backend/internal/controller/analytics"
"backend/internal/controller/auth"
"backend/internal/controller/customer"
"backend/internal/controller/entitlement"
"backend/internal/controller/license"
"backend/internal/controller/order"
"backend/internal/controller/plan"
"backend/internal/controller/product"
"backend/internal/controller/setting"
"backend/middleware"
"strings"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
)
// register 同时注册带和不带 trailing slash 的路由 // Logan.Li
func register(r gin.IRoutes, method, relativePath string, handlers ...gin.HandlerFunc) {
isParamRoute := strings.Contains(relativePath, ":")
switch method {
case "GET":
r.GET(relativePath, handlers...)
if !isParamRoute {
r.GET(relativePath+"/", handlers...)
}
case "POST":
r.POST(relativePath, handlers...)
if !isParamRoute {
r.POST(relativePath+"/", handlers...)
}
case "PUT":
r.PUT(relativePath, handlers...)
if !isParamRoute {
r.PUT(relativePath+"/", handlers...)
}
case "DELETE":
r.DELETE(relativePath, handlers...)
if !isParamRoute {
r.DELETE(relativePath+"/", handlers...)
}
case "PATCH":
r.PATCH(relativePath, handlers...)
if !isParamRoute {
r.PATCH(relativePath+"/", handlers...)
}
}
}
// SetupRouter 初始化路由 // Logan.Li
func SetupRouter(db *gorm.DB, cfg *config.Config) *gin.Engine {
gin.SetMode(cfg.Mode)
r := gin.Default()
r.RedirectTrailingSlash = false
r.RedirectFixedPath = false
// Gzip 压缩中间件 // Logan.Li
r.Use(gzip.Gzip(gzip.DefaultCompression))
// CORS 中间件 // Logan.Li
r.Use(middleware.CORSMiddleware(cfg))
// 健康检查 // Logan.Li
r.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"code": 0, "message": "ok", "data": nil})
})
// 初始化控制器 // Logan.Li
authController := auth.NewAuthController(db, cfg)
productController := product.NewProductController(db)
customerController := customer.NewCustomerController(db)
licenseController := license.NewLicenseController(db, cfg)
planController := plan.NewPlanController(db)
orderController := order.NewOrderController(db)
entitlementController := entitlement.NewEntitlementController(db)
analyticsController := analytics.NewAnalyticsController(db)
settingController := setting.NewSettingController(db)
api := r.Group("/api")
{
// ============ 认证路由(无需 JWT) ============
authGroup := api.Group("/auth")
{
register(authGroup, "POST", "/login", authController.Login)
}
// ============ 客户端授权契约(无需认证,供外部工具调用) ============
clientAPI := api.Group("/v1")
{
// License 验证 / 激活 / 停用 / 心跳
register(clientAPI, "POST", "/license/verify", licenseController.Verify)
register(clientAPI, "POST", "/license/activate", licenseController.ActivateDevice)
register(clientAPI, "POST", "/license/deactivate", licenseController.Deactivate)
register(clientAPI, "POST", "/license/heartbeat", licenseController.Heartbeat)
register(clientAPI, "POST", "/license/devices", licenseController.ListDevices)
// 产品定价查询(展示用)
register(clientAPI, "GET", "/products/code/:code", productController.GetByCode)
clientAPI.GET("/products/:product_id/plans", planController.GetByProduct)
// 订单与支付(客户端购买入口 + 支付回调)
register(clientAPI, "POST", "/orders", orderController.CreateOrder)
register(clientAPI, "POST", "/checkout", orderController.Checkout)
register(clientAPI, "POST", "/purchase/claim", orderController.ClaimPurchase)
register(clientAPI, "POST", "/webhooks/payment", orderController.PaymentWebhook)
register(clientAPI, "GET", "/webhooks/waffo", orderController.WaffoWebhookReady)
register(clientAPI, "POST", "/webhooks/waffo", orderController.WaffoWebhook)
register(clientAPI, "GET", "/purchase/success", orderController.PurchaseSuccess)
register(clientAPI, "POST", "/purchase/check", orderController.CheckDuplicatePurchase)
register(clientAPI, "POST", "/purchase/status", orderController.CheckPurchaseStatus)
// 客户权益查询(通过邮箱)
register(clientAPI, "GET", "/entitlements/my", entitlementController.GetByEmail)
}
// ============ 需要认证的管理路由 ============
protected := api.Group("", middleware.AuthMiddleware(cfg))
{
// 认证相关
register(protected, "GET", "/auth/me", authController.Me)
register(protected, "PUT", "/auth/password", authController.ChangePassword)
// 产品管理
products := protected.Group("/products")
{
register(products, "GET", "", productController.List)
register(products, "GET", "/all", productController.GetAll)
register(products, "POST", "", productController.Create)
register(products, "GET", "/:id", productController.Get)
register(products, "PUT", "/:id", productController.Update)
register(products, "DELETE", "/:id", productController.Delete)
register(products, "PATCH", "/:id/status", productController.UpdateStatus)
}
// 客户管理
customers := protected.Group("/customers")
{
register(customers, "GET", "", customerController.List)
register(customers, "GET", "/all", customerController.GetAll)
register(customers, "POST", "", customerController.Create)
register(customers, "GET", "/:id", customerController.Get)
register(customers, "PUT", "/:id", customerController.Update)
register(customers, "DELETE", "/:id", customerController.Delete)
register(customers, "PATCH", "/:id/status", customerController.UpdateStatus)
}
// License 管理
licenses := protected.Group("/licenses")
{
register(licenses, "GET", "", licenseController.List)
register(licenses, "POST", "", licenseController.Create)
register(licenses, "POST", "/offline", licenseController.IssueOffline)
register(licenses, "GET", "/offline/public-key", licenseController.OfflinePublicKey)
register(licenses, "GET", "/export", licenseController.Export)
register(licenses, "GET", "/:id", licenseController.Get)
register(licenses, "PUT", "/:id", licenseController.Update)
register(licenses, "DELETE", "/:id", licenseController.Delete)
register(licenses, "POST", "/:id/renew", licenseController.Renew)
register(licenses, "POST", "/:id/revoke", licenseController.Revoke)
register(licenses, "POST", "/:id/suspend", licenseController.Suspend)
register(licenses, "POST", "/:id/activate", licenseController.Activate)
register(licenses, "GET", "/:id/activations", licenseController.GetActivations)
register(licenses, "POST", "/:id/activations/:activationId/offline", licenseController.ForceOffline)
}
// 定价计划管理
plans := protected.Group("/plans")
{
register(plans, "GET", "", planController.List)
register(plans, "POST", "", planController.Create)
register(plans, "PUT", "/:id", planController.Update)
register(plans, "DELETE", "/:id", planController.Delete)
register(plans, "PATCH", "/:id/status", planController.ToggleStatus)
}
// 订单管理
orders := protected.Group("/orders")
{
register(orders, "GET", "", orderController.List)
register(orders, "GET", "/:id", orderController.GetDetail)
register(orders, "POST", "/manual-grant", orderController.ManualGrant)
}
// 客户权益管理
entitlements := protected.Group("/entitlements")
{
register(entitlements, "GET", "", entitlementController.List)
register(entitlements, "GET", "/:id", entitlementController.Get)
register(entitlements, "POST", "/:id/revoke", entitlementController.Revoke)
register(entitlements, "POST", "/:id/renew", entitlementController.Renew)
}
// 仪表板与数据分析
dashboard := protected.Group("/dashboard")
{
register(dashboard, "GET", "/stats", analyticsController.GetDashboardStats)
register(dashboard, "GET", "/expiring", analyticsController.GetExpiringLicenses)
register(dashboard, "GET", "/activities", analyticsController.GetRecentActivities)
register(dashboard, "GET", "/online-stats", analyticsController.GetOnlineStats)
register(dashboard, "GET", "/revenue", analyticsController.GetRevenueStats)
}
analyticsGroup := protected.Group("/analytics")
{
register(analyticsGroup, "GET", "/license-growth", analyticsController.GetLicenseGrowth)
register(analyticsGroup, "GET", "/license-growth-detail", analyticsController.GetLicenseGrowthDetail)
register(analyticsGroup, "GET", "/product-distribution", analyticsController.GetProductDistribution)
register(analyticsGroup, "GET", "/geo-distribution", analyticsController.GetGeoDistribution)
register(analyticsGroup, "GET", "/platform-distribution", analyticsController.GetPlatformDistribution)
}
// 日志审计与系统设置
logs := protected.Group("/logs")
{
register(logs, "GET", "", settingController.ListAuditLogs)
register(logs, "DELETE", "/clear", settingController.ClearAuditLogs)
}
system := protected.Group("/settings")
{
register(system, "GET", "", settingController.Get)
register(system, "PUT", "", settingController.Update)
register(system, "GET", "/waffo", settingController.GetWaffo)
register(system, "PUT", "/waffo", settingController.UpdateWaffo)
register(system, "POST", "/waffo/test", settingController.DebugWaffo)
register(system, "GET", "/license-templates", settingController.ListLicenseTemplates)
register(system, "POST", "/license-templates", settingController.SaveLicenseTemplate)
register(system, "DELETE", "/license-templates/:id", settingController.DeleteLicenseTemplate)
}
// 支付调试(与 settings/waffo/test 同一 handler) // Logan.Li
paymentGroup := protected.Group("/payment")
{
register(paymentGroup, "POST", "/waffo/debug", settingController.DebugWaffo)
}
}
}
return r
}