From f45940cbc5abef6989519619ea50e82add8a5747 Mon Sep 17 00:00:00 2001 From: root Date: Mon, 9 Mar 2026 21:13:49 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20admin=20=E6=A8=A1=E5=9D=97=E6=8C=89?= =?UTF-8?q?=20handler/model/service=20=E5=88=86=E5=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/admin/admin.go | 56 +++++++++++++++++++ internal/admin/{ => handler}/auth_handler.go | 9 +-- .../{handler_base.go => handler/base.go} | 8 ++- internal/admin/{ => handler}/middleware.go | 9 +-- .../{ => handler}/mini_program_handler.go | 27 ++++----- internal/admin/{ => handler}/stats_handler.go | 2 +- internal/admin/{model.go => model/admin.go} | 2 +- internal/admin/{ => service}/auth_service.go | 20 ++++--- .../{ => service}/mini_program_service.go | 2 +- internal/admin/{ => service}/stats_service.go | 2 +- internal/admin/{ => service}/types.go | 2 +- 11 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 internal/admin/admin.go rename internal/admin/{ => handler}/auth_handler.go (89%) rename internal/admin/{handler_base.go => handler/base.go} (73%) rename internal/admin/{ => handler}/middleware.go (80%) rename internal/admin/{ => handler}/mini_program_handler.go (84%) rename internal/admin/{ => handler}/stats_handler.go (98%) rename internal/admin/{model.go => model/admin.go} (98%) rename internal/admin/{ => service}/auth_service.go (87%) rename internal/admin/{ => service}/mini_program_service.go (99%) rename internal/admin/{ => service}/stats_service.go (99%) rename internal/admin/{ => service}/types.go (98%) diff --git a/internal/admin/admin.go b/internal/admin/admin.go new file mode 100644 index 0000000..e5eeb19 --- /dev/null +++ b/internal/admin/admin.go @@ -0,0 +1,56 @@ +package admin + +import ( + "time" + + "github.com/gin-gonic/gin" + "gorm.io/gorm" + + adminhandler "wx_service/internal/admin/handler" + adminmodel "wx_service/internal/admin/model" + adminservice "wx_service/internal/admin/service" +) + +type Admin = adminmodel.Admin +type Handler = adminhandler.Handler +type Service = adminservice.Service +type Claims = adminservice.Claims + +type LoginResult = adminservice.LoginResult +type ListMiniProgramsQuery = adminservice.ListMiniProgramsQuery +type MiniProgramItem = adminservice.MiniProgramItem +type ListMiniProgramsResult = adminservice.ListMiniProgramsResult +type CreateMiniProgramInput = adminservice.CreateMiniProgramInput +type UpdateMiniProgramInput = adminservice.UpdateMiniProgramInput +type MiniProgramDetailStats = adminservice.MiniProgramDetailStats +type OverviewStats = adminservice.OverviewStats +type MiniProgramStatsItem = adminservice.MiniProgramStatsItem +type UserGrowthPoint = adminservice.UserGrowthPoint + +var ( + ErrInvalidCredentials = adminservice.ErrInvalidCredentials + ErrInvalidToken = adminservice.ErrInvalidToken + ErrMissingJWTSecret = adminservice.ErrMissingJWTSecret + ErrMiniProgramNotFound = adminservice.ErrMiniProgramNotFound + ErrMiniProgramHasUsers = adminservice.ErrMiniProgramHasUsers + ErrMiniProgramAppIDUsed = adminservice.ErrMiniProgramAppIDUsed + ErrInvalidInput = adminservice.ErrInvalidInput +) + +const ContextAdminClaimsKey = adminhandler.ContextAdminClaimsKey + +func NewService(db *gorm.DB, jwtSecret string, tokenTTL time.Duration, defaultUsername, defaultPassword string) *Service { + return adminservice.NewService(db, jwtSecret, tokenTTL, defaultUsername, defaultPassword) +} + +func NewHandler(svc *Service) *Handler { + return adminhandler.NewHandler(svc) +} + +func AuthMiddleware(svc *Service) gin.HandlerFunc { + return adminhandler.AuthMiddleware(svc) +} + +func CurrentAdminClaims(c *gin.Context) (*Claims, bool) { + return adminhandler.CurrentAdminClaims(c) +} diff --git a/internal/admin/auth_handler.go b/internal/admin/handler/auth_handler.go similarity index 89% rename from internal/admin/auth_handler.go rename to internal/admin/handler/auth_handler.go index d4ddd5f..1eccfba 100644 --- a/internal/admin/auth_handler.go +++ b/internal/admin/handler/auth_handler.go @@ -1,4 +1,4 @@ -package admin +package handler import ( "errors" @@ -6,6 +6,7 @@ import ( "github.com/gin-gonic/gin" + adminservice "wx_service/internal/admin/service" "wx_service/internal/model" ) @@ -24,11 +25,11 @@ func (h *Handler) Login(c *gin.Context) { result, err := h.svc.Login(c.Request.Context(), req.Username, req.Password) if err != nil { switch { - case errors.Is(err, ErrInvalidCredentials): + case errors.Is(err, adminservice.ErrInvalidCredentials): c.JSON(http.StatusUnauthorized, model.Error(http.StatusUnauthorized, "用户名或密码错误")) - case errors.Is(err, ErrMissingJWTSecret): + case errors.Is(err, adminservice.ErrMissingJWTSecret): c.JSON(http.StatusServiceUnavailable, model.Error(http.StatusServiceUnavailable, "管理员认证未配置,请检查 JWT_SECRET")) - case errors.Is(err, ErrInvalidInput): + case errors.Is(err, adminservice.ErrInvalidInput): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "用户名和密码不能为空")) default: c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "admin login failed")) diff --git a/internal/admin/handler_base.go b/internal/admin/handler/base.go similarity index 73% rename from internal/admin/handler_base.go rename to internal/admin/handler/base.go index 0ad54cf..a7c62f0 100644 --- a/internal/admin/handler_base.go +++ b/internal/admin/handler/base.go @@ -1,4 +1,4 @@ -package admin +package handler import ( "errors" @@ -6,13 +6,15 @@ import ( "strings" "github.com/gin-gonic/gin" + + adminservice "wx_service/internal/admin/service" ) type Handler struct { - svc *Service + svc *adminservice.Service } -func NewHandler(svc *Service) *Handler { +func NewHandler(svc *adminservice.Service) *Handler { return &Handler{svc: svc} } diff --git a/internal/admin/middleware.go b/internal/admin/handler/middleware.go similarity index 80% rename from internal/admin/middleware.go rename to internal/admin/handler/middleware.go index 71dae02..2f16238 100644 --- a/internal/admin/middleware.go +++ b/internal/admin/handler/middleware.go @@ -1,4 +1,4 @@ -package admin +package handler import ( "net/http" @@ -6,12 +6,13 @@ import ( "github.com/gin-gonic/gin" + adminservice "wx_service/internal/admin/service" "wx_service/internal/model" ) const ContextAdminClaimsKey = "adminClaims" -func AuthMiddleware(svc *Service) gin.HandlerFunc { +func AuthMiddleware(svc *adminservice.Service) gin.HandlerFunc { return func(c *gin.Context) { token := extractBearerToken(c.GetHeader("Authorization")) if token == "" { @@ -30,12 +31,12 @@ func AuthMiddleware(svc *Service) gin.HandlerFunc { } } -func CurrentAdminClaims(c *gin.Context) (*Claims, bool) { +func CurrentAdminClaims(c *gin.Context) (*adminservice.Claims, bool) { value, ok := c.Get(ContextAdminClaimsKey) if !ok { return nil, false } - claims, ok := value.(*Claims) + claims, ok := value.(*adminservice.Claims) return claims, ok } diff --git a/internal/admin/mini_program_handler.go b/internal/admin/handler/mini_program_handler.go similarity index 84% rename from internal/admin/mini_program_handler.go rename to internal/admin/handler/mini_program_handler.go index 8184651..a6553ff 100644 --- a/internal/admin/mini_program_handler.go +++ b/internal/admin/handler/mini_program_handler.go @@ -1,4 +1,4 @@ -package admin +package handler import ( "errors" @@ -8,6 +8,7 @@ import ( "github.com/gin-gonic/gin" + adminservice "wx_service/internal/admin/service" "wx_service/internal/model" ) @@ -15,7 +16,7 @@ func (h *Handler) ListMiniPrograms(c *gin.Context) { page, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("page", "1"))) pageSize, _ := strconv.Atoi(strings.TrimSpace(c.DefaultQuery("page_size", "20"))) - data, err := h.svc.ListMiniPrograms(c.Request.Context(), ListMiniProgramsQuery{ + data, err := h.svc.ListMiniPrograms(c.Request.Context(), adminservice.ListMiniProgramsQuery{ Page: page, PageSize: pageSize, Keyword: c.Query("keyword"), @@ -36,7 +37,7 @@ func (h *Handler) GetMiniProgram(c *gin.Context) { data, err := h.svc.GetMiniProgram(c.Request.Context(), id) if err != nil { - if errors.Is(err, ErrMiniProgramNotFound) { + if errors.Is(err, adminservice.ErrMiniProgramNotFound) { c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "mini program not found")) return } @@ -55,7 +56,7 @@ func (h *Handler) GetMiniProgramStats(c *gin.Context) { data, err := h.svc.GetMiniProgramStats(c.Request.Context(), id) if err != nil { - if errors.Is(err, ErrMiniProgramNotFound) { + if errors.Is(err, adminservice.ErrMiniProgramNotFound) { c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "mini program not found")) return } @@ -79,7 +80,7 @@ func (h *Handler) CreateMiniProgram(c *gin.Context) { return } - data, err := h.svc.CreateMiniProgram(c.Request.Context(), CreateMiniProgramInput{ + data, err := h.svc.CreateMiniProgram(c.Request.Context(), adminservice.CreateMiniProgramInput{ Name: req.Name, AppID: req.AppID, AppSecret: req.AppSecret, @@ -87,9 +88,9 @@ func (h *Handler) CreateMiniProgram(c *gin.Context) { }) if err != nil { switch { - case errors.Is(err, ErrInvalidInput): + case errors.Is(err, adminservice.ErrInvalidInput): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "name/app_id/app_secret are required")) - case errors.Is(err, ErrMiniProgramAppIDUsed): + case errors.Is(err, adminservice.ErrMiniProgramAppIDUsed): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "app_id already exists")) default: c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "create mini-program failed")) @@ -119,7 +120,7 @@ func (h *Handler) UpdateMiniProgram(c *gin.Context) { return } - data, err := h.svc.UpdateMiniProgram(c.Request.Context(), id, UpdateMiniProgramInput{ + data, err := h.svc.UpdateMiniProgram(c.Request.Context(), id, adminservice.UpdateMiniProgramInput{ Name: req.Name, AppID: req.AppID, AppSecret: req.AppSecret, @@ -127,11 +128,11 @@ func (h *Handler) UpdateMiniProgram(c *gin.Context) { }) if err != nil { switch { - case errors.Is(err, ErrMiniProgramNotFound): + case errors.Is(err, adminservice.ErrMiniProgramNotFound): c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "mini program not found")) - case errors.Is(err, ErrInvalidInput): + case errors.Is(err, adminservice.ErrInvalidInput): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "name/app_id are required")) - case errors.Is(err, ErrMiniProgramAppIDUsed): + case errors.Is(err, adminservice.ErrMiniProgramAppIDUsed): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "app_id already exists")) default: c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "update mini-program failed")) @@ -151,9 +152,9 @@ func (h *Handler) DeleteMiniProgram(c *gin.Context) { err = h.svc.DeleteMiniProgram(c.Request.Context(), id) if err != nil { switch { - case errors.Is(err, ErrMiniProgramNotFound): + case errors.Is(err, adminservice.ErrMiniProgramNotFound): c.JSON(http.StatusNotFound, model.Error(http.StatusNotFound, "mini program not found")) - case errors.Is(err, ErrMiniProgramHasUsers): + case errors.Is(err, adminservice.ErrMiniProgramHasUsers): c.JSON(http.StatusBadRequest, model.Error(http.StatusBadRequest, "mini program has related users")) default: c.JSON(http.StatusInternalServerError, model.Error(http.StatusInternalServerError, "delete mini-program failed")) diff --git a/internal/admin/stats_handler.go b/internal/admin/handler/stats_handler.go similarity index 98% rename from internal/admin/stats_handler.go rename to internal/admin/handler/stats_handler.go index ac4782e..5060d30 100644 --- a/internal/admin/stats_handler.go +++ b/internal/admin/handler/stats_handler.go @@ -1,4 +1,4 @@ -package admin +package handler import ( "net/http" diff --git a/internal/admin/model.go b/internal/admin/model/admin.go similarity index 98% rename from internal/admin/model.go rename to internal/admin/model/admin.go index 71a2c09..6c1de50 100644 --- a/internal/admin/model.go +++ b/internal/admin/model/admin.go @@ -1,4 +1,4 @@ -package admin +package model import ( "time" diff --git a/internal/admin/auth_service.go b/internal/admin/service/auth_service.go similarity index 87% rename from internal/admin/auth_service.go rename to internal/admin/service/auth_service.go index 10d9a6f..78a9d4b 100644 --- a/internal/admin/auth_service.go +++ b/internal/admin/service/auth_service.go @@ -1,4 +1,4 @@ -package admin +package service import ( "context" @@ -7,6 +7,8 @@ import ( "strings" "time" + adminmodel "wx_service/internal/admin/model" + "github.com/golang-jwt/jwt/v5" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" @@ -14,7 +16,7 @@ import ( func (s *Service) EnsureDefaultAdmin(ctx context.Context) error { var count int64 - if err := s.db.WithContext(ctx).Model(&Admin{}).Count(&count).Error; err != nil { + if err := s.db.WithContext(ctx).Model(&adminmodel.Admin{}).Count(&count).Error; err != nil { return err } if count > 0 { @@ -35,7 +37,7 @@ func (s *Service) EnsureDefaultAdmin(ctx context.Context) error { return err } - record := &Admin{ + record := &adminmodel.Admin{ Username: username, Password: string(hashedPassword), Role: "super_admin", @@ -50,8 +52,8 @@ func (s *Service) EnsureDefaultAdmin(ctx context.Context) error { } type LoginResult struct { - Token string `json:"token"` - Admin *Admin `json:"admin"` + Token string `json:"token"` + Admin *adminmodel.Admin `json:"admin"` } func (s *Service) Login(ctx context.Context, username, password string) (*LoginResult, error) { @@ -60,7 +62,7 @@ func (s *Service) Login(ctx context.Context, username, password string) (*LoginR return nil, ErrInvalidInput } - var admin Admin + var admin adminmodel.Admin if err := s.db.WithContext(ctx).Where("username = ?", username).First(&admin).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, ErrInvalidCredentials @@ -111,7 +113,7 @@ func (s *Service) ParseToken(token string) (*Claims, error) { return claims, nil } -func (s *Service) generateToken(admin *Admin) (string, error) { +func (s *Service) generateToken(admin *adminmodel.Admin) (string, error) { if len(s.jwtSecret) == 0 { return "", ErrMissingJWTSecret } @@ -132,8 +134,8 @@ func (s *Service) generateToken(admin *Admin) (string, error) { return t.SignedString(s.jwtSecret) } -func (s *Service) GetProfile(ctx context.Context, adminID uint) (*Admin, error) { - var admin Admin +func (s *Service) GetProfile(ctx context.Context, adminID uint) (*adminmodel.Admin, error) { + var admin adminmodel.Admin if err := s.db.WithContext(ctx). Select("id", "username", "role", "last_login_at", "created_at", "updated_at"). Where("id = ?", adminID). diff --git a/internal/admin/mini_program_service.go b/internal/admin/service/mini_program_service.go similarity index 99% rename from internal/admin/mini_program_service.go rename to internal/admin/service/mini_program_service.go index e3e5c1a..abc73c0 100644 --- a/internal/admin/mini_program_service.go +++ b/internal/admin/service/mini_program_service.go @@ -1,4 +1,4 @@ -package admin +package service import ( "context" diff --git a/internal/admin/stats_service.go b/internal/admin/service/stats_service.go similarity index 99% rename from internal/admin/stats_service.go rename to internal/admin/service/stats_service.go index 4d05a49..b2c8026 100644 --- a/internal/admin/stats_service.go +++ b/internal/admin/service/stats_service.go @@ -1,4 +1,4 @@ -package admin +package service import ( "context" diff --git a/internal/admin/types.go b/internal/admin/service/types.go similarity index 98% rename from internal/admin/types.go rename to internal/admin/service/types.go index bf96591..db8bf64 100644 --- a/internal/admin/types.go +++ b/internal/admin/service/types.go @@ -1,4 +1,4 @@ -package admin +package service import ( "errors"