223 lines
14 KiB
Go
223 lines
14 KiB
Go
package router
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"affiliate_dash/internal/handler"
|
|
"affiliate_dash/internal/middleware"
|
|
"affiliate_dash/internal/model"
|
|
"affiliate_dash/internal/pkg/jwt"
|
|
"affiliate_dash/internal/service"
|
|
|
|
"github.com/gin-contrib/cors"
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type Handlers struct {
|
|
Auth *handler.AuthHandler
|
|
Dashboard *handler.DashboardHandler
|
|
Delivery *handler.DeliveryHandler
|
|
User *handler.UserHandler
|
|
Open *handler.OpenV1Handler
|
|
SourceOpen *handler.OpenHandler
|
|
Merchant *handler.MerchantHandler
|
|
Recharge *handler.RechargeHandler
|
|
JWT *jwt.Manager
|
|
Tenant *service.TenantService
|
|
OpenDB *gorm.DB
|
|
SecretCodec *service.SecretCodec
|
|
OpenAPIKey string
|
|
OpenAPISecret string
|
|
OpenSignSkew int64
|
|
OpenAPIDebug bool
|
|
UploadDir string
|
|
// CORSAllowedOrigins 跨域来源白名单;为空时使用本地开发默认来源。
|
|
CORSAllowedOrigins []string
|
|
}
|
|
|
|
// defaultCORSOrigins 未配置 CORS_ALLOWED_ORIGINS 时的本地开发默认来源。
|
|
var defaultCORSOrigins = []string{
|
|
"http://localhost:15173",
|
|
"http://127.0.0.1:15173",
|
|
"http://localhost:18080",
|
|
"http://127.0.0.1:18080",
|
|
}
|
|
|
|
// corsOrigins 返回生效的 CORS 来源白名单,并拒绝通配符 "*"
|
|
// (与 AllowCredentials 组合会让浏览器把凭证请求放行给任意站点)。
|
|
func corsOrigins(h *Handlers) []string {
|
|
var origins []string
|
|
for _, o := range h.CORSAllowedOrigins {
|
|
o = strings.TrimSpace(o)
|
|
if o == "" || o == "*" {
|
|
continue
|
|
}
|
|
origins = append(origins, o)
|
|
}
|
|
if len(origins) == 0 {
|
|
return defaultCORSOrigins
|
|
}
|
|
return origins
|
|
}
|
|
|
|
// requestLogger 访问日志中间件:跳过 /health 健康检查(每 30 秒一次,避免刷屏)。
|
|
func requestLogger() gin.HandlerFunc {
|
|
inner := gin.Logger()
|
|
return func(c *gin.Context) {
|
|
if c.Request.URL.Path == "/health" {
|
|
c.Next()
|
|
return
|
|
}
|
|
inner(c)
|
|
}
|
|
}
|
|
|
|
func Setup(h *Handlers) *gin.Engine {
|
|
r := gin.New()
|
|
r.Use(requestLogger(), gin.Recovery())
|
|
|
|
r.Use(cors.New(cors.Config{
|
|
AllowOrigins: corsOrigins(h),
|
|
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"},
|
|
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Merchant-ID", "X-App-Key", "X-Api-Key", "X-Timestamp", "X-Nonce", "X-Sign", "X-Request-ID"},
|
|
ExposeHeaders: []string{"Content-Length", "X-Request-ID"},
|
|
AllowCredentials: true,
|
|
}))
|
|
|
|
r.GET("/health", func(c *gin.Context) {
|
|
c.JSON(200, gin.H{"status": "ok"})
|
|
})
|
|
|
|
// 上传的凭证等静态文件(公开访问,文件名不可枚举)
|
|
if h.UploadDir != "" {
|
|
r.Static("/uploads", h.UploadDir)
|
|
}
|
|
|
|
api := r.Group("/api")
|
|
{
|
|
api.POST("/auth/login", h.Auth.Login)
|
|
|
|
// 用户侧公开发货页接口:商户把发货链接给用户,用户只填写游戏 UID。
|
|
delivery := api.Group("/delivery/v1")
|
|
{
|
|
delivery.GET("/orders/:order_no", h.Delivery.GetOrder)
|
|
delivery.POST("/orders/:order_no/bind", h.Delivery.Bind)
|
|
delivery.POST("/orders/:order_no/submit", h.Delivery.Submit)
|
|
}
|
|
|
|
// 源头侧接口:上游发货平台查询订单并回传发货结果。
|
|
sourceOpen := api.Group("/open/v1")
|
|
sourceOpen.Use(middleware.SourceOpenAuth(middleware.SourceOpenAuthConfig{
|
|
DB: h.OpenDB,
|
|
APIKey: h.OpenAPIKey,
|
|
APISecret: h.OpenAPISecret,
|
|
SkewSeconds: h.OpenSignSkew,
|
|
Debug: h.OpenAPIDebug,
|
|
}))
|
|
{
|
|
sourceOpen.GET("/orders/:order_no", h.SourceOpen.QueryOrder)
|
|
sourceOpen.POST("/orders/ship-notify", h.SourceOpen.ShipNotify)
|
|
}
|
|
|
|
// 商户侧接口:每个商户独立 API 客户端 + HMAC 签名。
|
|
clientOpen := api.Group("/client/v1")
|
|
clientOpen.Use(middleware.OpenAuth(middleware.OpenAuthConfig{
|
|
DB: h.OpenDB,
|
|
Codec: h.SecretCodec,
|
|
SkewSeconds: h.OpenSignSkew,
|
|
Debug: h.OpenAPIDebug,
|
|
}))
|
|
{
|
|
clientOpen.GET("/products", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureProducts), middleware.RequireAPIScope("products:read"), h.Open.ListProducts)
|
|
clientOpen.POST("/orders", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:write"), h.Open.CreateOrder)
|
|
clientOpen.GET("/orders/:order_no", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:read", "shipping:read"), h.Open.QueryOrder)
|
|
clientOpen.POST("/orders/:order_no/cancel", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:write"), h.Open.CancelOrder)
|
|
clientOpen.GET("/orders/:order_no/delivery-link", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:read", "shipping:read"), h.Open.GetDeliveryLink)
|
|
clientOpen.GET("/orders/:order_no/delivery", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:read", "shipping:read"), h.Open.GetDeliveryOrder)
|
|
clientOpen.POST("/orders/:order_no/delivery/bind", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:write"), h.Open.BindDeliveryOrder)
|
|
clientOpen.GET("/orders/:order_no/delivery/bind-result", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:read", "shipping:read"), h.Open.GetDeliveryBindResult)
|
|
clientOpen.POST("/orders/:order_no/delivery/submit", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireAPIScope("orders:write"), h.Open.SubmitDeliveryOrder)
|
|
clientOpen.GET("/wallet", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireAPIScope("wallet:read"), h.Open.GetWallet)
|
|
}
|
|
|
|
auth := api.Group("")
|
|
auth.Use(middleware.Auth(h.JWT))
|
|
auth.Use(middleware.Tenant(h.Tenant))
|
|
{
|
|
auth.GET("/auth/profile", h.Auth.Profile)
|
|
auth.PUT("/auth/account", h.Auth.UpdateCurrentAccount)
|
|
auth.PUT("/auth/password", h.Auth.ChangePassword)
|
|
auth.GET("/dashboard", h.Dashboard.Dashboard)
|
|
|
|
// 商户后台:商户就是平台下游客户,成员只代表该商户内部员工。
|
|
merchant := auth.Group("/merchant")
|
|
{
|
|
merchant.GET("", h.Merchant.Current)
|
|
merchant.GET("/products", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureProducts), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionProductsManage), h.Merchant.ListProducts)
|
|
merchant.PATCH("/products/:id/status", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureProducts), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionProductsManage), h.Merchant.UpdateProductStatus)
|
|
merchant.GET("/orders", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.ListOrders)
|
|
merchant.GET("/orders/products", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.ListManualOrderProducts)
|
|
merchant.POST("/orders/manual", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.CreateManualOrder)
|
|
merchant.POST("/orders/test", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.CreateTestOrder)
|
|
merchant.GET("/orders/:order_no/delivery-link", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.GetDeliveryLink)
|
|
merchant.POST("/orders/:order_no/delivery-link/revoke", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.RevokeDeliveryLink)
|
|
merchant.POST("/orders/:order_no/delivery-link/restore", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureOrders), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionOrdersManage), h.Merchant.RestoreDeliveryLink)
|
|
merchant.GET("/wallet", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionWalletView), h.Merchant.GetWallet)
|
|
merchant.GET("/wallet/ledger", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionWalletLedger), h.Merchant.ListWalletLedger)
|
|
merchant.POST("/recharge/applications", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.CreateApplication)
|
|
merchant.GET("/recharge/applications", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionWalletView), h.Recharge.ListApplications)
|
|
merchant.GET("/recharge/alert-config", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.GetAlertConfig)
|
|
merchant.PUT("/recharge/alert-config", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.SaveAlertConfig)
|
|
merchant.GET("/alert-channels", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.ListAlertChannels)
|
|
merchant.POST("/alert-channels", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.CreateAlertChannel)
|
|
merchant.PUT("/alert-channels/:id", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.UpdateAlertChannel)
|
|
merchant.DELETE("/alert-channels/:id", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.DeleteAlertChannel)
|
|
merchant.POST("/alert-channels/:id/test", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureWallet), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionRechargeManage), h.Recharge.TestAlertChannel)
|
|
merchant.GET("/api-clients", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureAPI), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionAPIManage), h.Merchant.ListAPIClients)
|
|
merchant.POST("/api-clients", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureAPI), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionAPIManage), h.Merchant.CreateAPIClient)
|
|
merchant.PATCH("/api-clients/:id/status", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureAPI), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionAPIManage), h.Merchant.UpdateAPIClientStatus)
|
|
merchant.DELETE("/api-clients/:id", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureAPI), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionAPIManage), h.Merchant.DeleteAPIClient)
|
|
merchant.GET("/callbacks", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureCallbacks), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionCallbacksManage), h.Merchant.ListCallbacks)
|
|
merchant.POST("/callbacks", middleware.RequireMerchantFeature(h.OpenDB, model.MerchantFeatureCallbacks), middleware.RequireMerchantPermissions(h.Tenant, model.PermissionCallbacksManage), h.Merchant.CreateCallback)
|
|
merchant.GET("/members", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.ListMembers)
|
|
merchant.POST("/members", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.AddCurrentMerchantMember)
|
|
merchant.PATCH("/members/:id", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.UpdateCurrentMerchantMember)
|
|
merchant.DELETE("/members/:id", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.RemoveCurrentMerchantMember)
|
|
merchant.GET("/roles", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.ListRoles)
|
|
merchant.POST("/roles", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.CreateRole)
|
|
merchant.PATCH("/roles/:id", middleware.RequireMerchantPermissions(h.Tenant, model.PermissionMembersManage), h.Merchant.UpdateRole)
|
|
}
|
|
|
|
// 平台管理员 / 发货记录 / 平台商户(仅管理员)
|
|
admin := auth.Group("")
|
|
admin.Use(middleware.RequireRole(model.RoleAdmin))
|
|
{
|
|
admin.GET("/platform/admins", h.User.ListPlatformAdmins)
|
|
admin.GET("/platform/merchant-accounts", h.User.ListMerchantAccountGroups)
|
|
admin.DELETE("/platform/merchant-accounts/:id", h.User.DeleteMerchantAccount)
|
|
admin.POST("/platform/admins", h.User.CreatePlatformAdmin)
|
|
admin.PATCH("/platform/admins/:id", h.User.UpdatePlatformAdmin)
|
|
admin.DELETE("/platform/admins/:id", h.User.DeletePlatformAdmin)
|
|
admin.GET("/platform/merchants", h.Merchant.ListPlatformMerchants)
|
|
admin.POST("/platform/merchants", h.Merchant.CreateMerchant)
|
|
admin.PATCH("/platform/merchants/:id", h.Merchant.UpdateMerchantSettings)
|
|
admin.POST("/platform/merchants/:id/members", h.Merchant.AddPlatformMerchantMember)
|
|
admin.GET("/platform/product-catalog", h.Merchant.ListProductCatalog)
|
|
admin.GET("/platform/merchants/:id/products", h.Merchant.ListMerchantProductsByAdmin)
|
|
admin.PATCH("/platform/merchants/:id/products/:pid", h.Merchant.AdminUpdateMerchantProduct)
|
|
admin.POST("/platform/merchants/:id/products/assign", h.Merchant.AssignProducts)
|
|
admin.GET("/platform/merchants/:id/wallet", h.Merchant.AdminGetWallet)
|
|
admin.GET("/platform/merchants/:id/wallet/ledger", h.Merchant.AdminListWalletLedger)
|
|
admin.POST("/platform/merchants/:id/wallet/adjust", h.Merchant.AdminAdjustWallet)
|
|
admin.GET("/platform/recharge/applications", h.Recharge.AdminListApplications)
|
|
admin.POST("/platform/recharge/applications/:id/review", h.Recharge.AdminReviewApplication)
|
|
}
|
|
|
|
auth.POST("/upload", h.Recharge.Upload)
|
|
}
|
|
}
|
|
|
|
return r
|
|
}
|