diff --git a/cmd/build/build.go b/cmd/build/build.go new file mode 100644 index 0000000..e6394e4 --- /dev/null +++ b/cmd/build/build.go @@ -0,0 +1,113 @@ +package build + +import ( + "net/http" + + "management/internal/erpserver/handler" + "management/internal/erpserver/repository" + "management/internal/erpserver/repository/seed" + "management/internal/erpserver/repository/system" + v1 "management/internal/erpserver/service/v1" + "management/internal/erpserver/service/v1/common" + system2 "management/internal/erpserver/service/v1/system" + "management/internal/pkg/cache" + "management/internal/pkg/config" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" +) + +func Initialize(conf *config.Config, log *logger.Logger) (http.Handler, func(), error) { + db, cleanup, err := repository.NewDB(conf, log) + if err != nil { + return nil, nil, err + } + + rd, cleanup2, err := cache.ConnectRedis(conf, log) + if err != nil { + cleanup() + return nil, nil, err + } + + sm, err := session.NewSCSManager(rd, conf) + if err != nil { + cleanup2() + cleanup() + return nil, nil, err + } + + redisCache := cache.NewRedisCache(rd) + + // ================================================================================================================= + // repo + + repo := repository.NewRepository(db, log) + transaction := repository.NewTransaction(repo) + + userRepository := system.NewUserRepository(repo) + roleRepository := system.NewRoleRepository(repo) + menuRepository := system.NewMenuRepository(repo) + roleMenuRepository := system.NewRoleMenuRepository(repo) + departmentRepository := system.NewDepartmentRepository(repo) + configRepository := system.NewConfigRepository(repo) + loginLogRepository := system.NewLoginLogRepository(repo) + auditLogRepository := system.NewAuditLogRepository(repo) + + sd := seed.NewSeed(configRepository, departmentRepository, roleRepository, userRepository, menuRepository) + if err := sd.Run(); err != nil { + cleanup2() + cleanup() + return nil, nil, err + } + + // ================================================================================================================= + // service + + service := v1.NewService(log, transaction, sm, redisCache) + + loginLogService := system2.NewLoginLogService(service, loginLogRepository) + roleMenuService := system2.NewRoleMenuService(service, roleMenuRepository) + roleService := system2.NewRoleService(service, roleRepository) + userService := system2.NewUserService(service, userRepository, roleService, loginLogService) + menuService := system2.NewMenuService(service, menuRepository, roleService, roleMenuService) + departmentService := system2.NewDepartmentService(service, departmentRepository) + configService := system2.NewConfigService(service, configRepository) + captchaService := common.NewCaptchaService() + auditLogService := system2.NewAuditLogService(service, auditLogRepository) + + // ================================================================================================================= + // mid + + // 初始化审计缓冲器 + mid.InitAuditBuffer(auditLogService, log) + + // ================================================================================================================= + // render + + rdr := render.NewRender(log) + + // ================================================================================================================= + // app route + + cfg := handler.Config{ + Conf: conf, + Log: log, + Sm: sm, + Render: rdr, + CaptchaService: captchaService, + UserService: userService, + RoleService: roleService, + DepartmentService: departmentService, + MenuService: menuService, + ConfigService: configService, + AuditLogService: auditLogService, + LoginLogService: loginLogService, + } + app := handler.WebApp(cfg) + return app, func() { + cleanup2() + cleanup() + }, nil +} diff --git a/cmd/erp.go b/cmd/erp.go index 6f11ff3..82f7bbf 100644 --- a/cmd/erp.go +++ b/cmd/erp.go @@ -7,9 +7,8 @@ import ( "runtime" "time" - "management/internal/erpserver" + "management/cmd/build" "management/internal/pkg/config" - "management/internal/pkg/mid" "github.com/drhin/logger" "github.com/fvbock/endless" @@ -51,34 +50,26 @@ func runErp() error { return err } - app, fn, err := erpserver.NewWire(conf, l) + app, fn, err := build.Initialize(conf, l) if err != nil { return err } defer fn() - // database seed - if err := app.Seed.Run(); err != nil { - return err - } - - // 初始化审计缓冲器 - mid.InitAuditBuffer(app.AuditLogService, l) - address := fmt.Sprintf("%s:%d", conf.App.Host, conf.App.Port) log.Printf("Starting manage server on %s", address) if runtime.GOOS == "windows" { s := &http.Server{ Addr: address, - Handler: app.Router, + Handler: app, ReadTimeout: 20 * time.Second, WriteTimeout: 20 * time.Second, MaxHeaderBytes: 1 << 20, } return s.ListenAndServe() } else { - s := endless.NewServer(address, app.Router) + s := endless.NewServer(address, app) s.ReadHeaderTimeout = 20 * time.Second s.WriteTimeout = 20 * time.Second s.MaxHeaderBytes = 1 << 20 diff --git a/go.mod b/go.mod index dbf0075..30f6373 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,6 @@ require ( github.com/redis/go-redis/v9 v9.10.0 github.com/spf13/cobra v1.9.1 github.com/spf13/viper v1.20.1 - github.com/tdewolff/minify v2.3.6+incompatible github.com/zhang2092/browser v0.0.2 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.39.0 @@ -60,8 +59,6 @@ require ( github.com/spf13/cast v1.9.2 // indirect github.com/spf13/pflag v1.0.6 // indirect github.com/subosito/gotenv v1.6.0 // indirect - github.com/tdewolff/parse v2.3.4+incompatible // indirect - github.com/tdewolff/test v1.0.11 // indirect go.uber.org/multierr v1.11.0 // indirect golang.org/x/image v0.28.0 // indirect golang.org/x/net v0.41.0 // indirect diff --git a/go.sum b/go.sum index 2156df3..6dd78b6 100644 --- a/go.sum +++ b/go.sum @@ -140,12 +140,6 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -github.com/tdewolff/minify v2.3.6+incompatible h1:2hw5/9ZvxhWLvBUnHE06gElGYz+Jv9R4Eys0XUzItYo= -github.com/tdewolff/minify v2.3.6+incompatible/go.mod h1:9Ov578KJUmAWpS6NeZwRZyT56Uf6o3Mcz9CEsg8USYs= -github.com/tdewolff/parse v2.3.4+incompatible h1:x05/cnGwIMf4ceLuDMBOdQ1qGniMoxpP46ghf0Qzh38= -github.com/tdewolff/parse v2.3.4+incompatible/go.mod h1:8oBwCsVmUkgHO8M5iCzSIDtpzXOT0WXX9cWhz+bIzJQ= -github.com/tdewolff/test v1.0.11 h1:FdLbwQVHxqG16SlkGveC0JVyrJN62COWTRyUFzfbtBE= -github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zhang2092/browser v0.0.2 h1:4jyWWkSCabGxqn74lCDvNnA4o9TlmsUXuwQHPZFsflQ= github.com/zhang2092/browser v0.0.2/go.mod h1:k/HIdVgWmpi9WvGuIU8pu8aK4rMCI4vr0ICCsk5H8T8= diff --git a/internal/erpserver/app.go b/internal/erpserver/app.go deleted file mode 100644 index fed2847..0000000 --- a/internal/erpserver/app.go +++ /dev/null @@ -1,32 +0,0 @@ -package erpserver - -import ( - "management/internal/erpserver/repository/seed" - v1 "management/internal/erpserver/service/v1" - - "github.com/go-chi/chi/v5" -) - -type App struct { - Seed *seed.Seed - - AuditLogService v1.AuditLogService - - Router *chi.Mux -} - -func NewApp( - Seed *seed.Seed, - - AuditLogService v1.AuditLogService, - - Router *chi.Mux, -) App { - return App{ - Seed: Seed, - - AuditLogService: AuditLogService, - - Router: Router, - } -} diff --git a/internal/erpserver/handler/captcha/captcha.go b/internal/erpserver/handler/captcha/captcha.go new file mode 100644 index 0000000..bf790e2 --- /dev/null +++ b/internal/erpserver/handler/captcha/captcha.go @@ -0,0 +1,50 @@ +package captcha + +import ( + "net/http" + + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/config" + "management/internal/pkg/render" +) + +type App struct { + config *config.Config + render render.Renderer + captchaService v1.CaptchaService +} + +func NewApp(config *config.Config, render render.Renderer, captchaService v1.CaptchaService) *App { + return &App{ + config: config, + render: render, + captchaService: captchaService, + } +} + +type Response struct { + CaptchaID string `json:"captcha_id"` + PicPath string `json:"pic_path"` + CaptchaLength int `json:"captcha_length"` + OpenCaptcha int `json:"open_captcha"` +} + +func (a *App) captcha(w http.ResponseWriter, _ *http.Request) { + id, b64s, _, err := a.captchaService.Generate( + a.config.Captcha.ImgHeight, + a.config.Captcha.ImgWidth, + a.config.Captcha.KeyLong, + 0.7, 80) + if err != nil { + a.render.JSONErr(w, "获取验证码失败") + return + } + + rsp := Response{ + CaptchaID: id, + PicPath: b64s, + CaptchaLength: a.config.Captcha.KeyLong, + OpenCaptcha: a.config.Captcha.OpenCaptcha, + } + a.render.JSONObj(w, "ok", rsp) +} diff --git a/internal/erpserver/handler/captcha/route.go b/internal/erpserver/handler/captcha/route.go new file mode 100644 index 0000000..8926b3a --- /dev/null +++ b/internal/erpserver/handler/captcha/route.go @@ -0,0 +1,20 @@ +package captcha + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/config" + "management/internal/pkg/render" + + "github.com/go-chi/chi/v5" +) + +type Config struct { + Conf *config.Config + Render render.Renderer + CaptchaService v1.CaptchaService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Conf, cfg.Render, cfg.CaptchaService) + r.Get("/captcha", app.captcha) +} diff --git a/internal/erpserver/handler/common/captcha.go b/internal/erpserver/handler/common/captcha.go deleted file mode 100644 index 32ee96b..0000000 --- a/internal/erpserver/handler/common/captcha.go +++ /dev/null @@ -1,47 +0,0 @@ -package common - -import ( - "net/http" - - "management/internal/erpserver/handler" - v1 "management/internal/erpserver/service/v1" -) - -type CaptchaHandler struct { - *handler.Handler - captchaService v1.CaptchaService -} - -func NewCaptchaHandler(handler *handler.Handler, captchaService v1.CaptchaService) *CaptchaHandler { - return &CaptchaHandler{ - Handler: handler, - captchaService: captchaService, - } -} - -type CaptchaResponse struct { - CaptchaID string `json:"captcha_id"` - PicPath string `json:"pic_path"` - CaptchaLength int `json:"captcha_length"` - OpenCaptcha int `json:"open_captcha"` -} - -func (h *CaptchaHandler) Captcha(w http.ResponseWriter, _ *http.Request) { - id, b64s, _, err := h.captchaService.Generate( - h.Config.Captcha.ImgHeight, - h.Config.Captcha.ImgWidth, - h.Config.Captcha.KeyLong, - 0.7, 80) - if err != nil { - h.JSONErr(w, "获取验证码失败") - return - } - - rsp := CaptchaResponse{ - CaptchaID: id, - PicPath: b64s, - CaptchaLength: h.Config.Captcha.KeyLong, - OpenCaptcha: h.Config.Captcha.OpenCaptcha, - } - h.JSONObj(w, "ok", rsp) -} diff --git a/internal/erpserver/handler/common/upload.go b/internal/erpserver/handler/common/upload.go deleted file mode 100644 index 530323e..0000000 --- a/internal/erpserver/handler/common/upload.go +++ /dev/null @@ -1,119 +0,0 @@ -package common - -import ( - "io" - "mime/multipart" - "net/http" - - "management/internal/erpserver/handler" - fileutil "management/internal/pkg/file" -) - -type UploadHandler struct { - *handler.Handler -} - -func NewUploadHandler(handler *handler.Handler) *UploadHandler { - return &UploadHandler{ - Handler: handler, - } -} - -const maxImageSize = 100 << 20 // 100 MB - -func (h *UploadHandler) Img(w http.ResponseWriter, r *http.Request) { - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - h.Log.Error(err.Error(), err) - } - }(r.Body) - - _, fh, err := r.FormFile("files") - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - path, err := fileutil.UploadFile(fh, fileutil.IMG) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - h.JSONObj(w, "ok", path) -} - -func (h *UploadHandler) File(w http.ResponseWriter, r *http.Request) { - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - h.Log.Error(err.Error(), err) - } - }(r.Body) - - _, fh, err := r.FormFile("files") - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - path, err := fileutil.UploadFile(fh, fileutil.ALL) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - h.JSONObj(w, "ok", path) -} - -type UploadFileRes struct { - Name string `json:"name"` - Path string `json:"path"` -} - -func (h *UploadHandler) MultiFiles(w http.ResponseWriter, r *http.Request) { - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - h.Log.Error(err.Error(), err) - } - }(r.Body) - - err := r.ParseMultipartForm(int64(maxImageSize)) - if err != nil { - return - } - files := r.MultipartForm.File["files"] - - var res []UploadFileRes - c := make(chan UploadFileRes, 2) - defer close(c) - - for i, file := range files { - go func(item *multipart.FileHeader, key int) { - ufr := UploadFileRes{Name: item.Filename} - - filePath, err := fileutil.UploadFile(item, fileutil.ALL) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - ufr.Path = filePath - c <- ufr - }(file, i) - } - - for { - v, ok := <-c - if ok { - res = append(res, v) - } - if len(files) == len(res) { - break - } - } - - h.JSONObj(w, "ok", res) -} diff --git a/internal/erpserver/handler/handler.go b/internal/erpserver/handler/handler.go deleted file mode 100644 index 19a18e5..0000000 --- a/internal/erpserver/handler/handler.go +++ /dev/null @@ -1,125 +0,0 @@ -package handler - -import ( - "context" - "encoding/json" - "fmt" - "net/http" - - "management/internal/erpserver/model/dto" - "management/internal/pkg/config" - "management/internal/pkg/know" - "management/internal/pkg/session" - - "github.com/a-h/templ" - "github.com/drhin/logger" - "go.uber.org/zap" -) - -//type RouterGroup interface { -// Register(router chi.Router) -//} - -type Handler struct { - Config *config.Config - Log *logger.Logger - - session session.Manager -} - -func NewHandler( - config *config.Config, - log *logger.Logger, - session session.Manager, -) *Handler { - return &Handler{ - Config: config, - Log: log, - session: session, - } -} - -// ===================================================================================================================== -// mid 帮助方法 - -func (h *Handler) AuthUser(ctx context.Context) dto.AuthorizeUser { - u, err := h.session.GetUser(ctx, know.StoreName) - if err != nil { - return dto.AuthorizeUser{} - } - return u -} - -func (h *Handler) RenewToken(ctx context.Context) error { - return h.session.RenewToken(ctx) -} - -func (h *Handler) Destroy(ctx context.Context) error { - return h.session.Destroy(ctx) -} - -// ===================================================================================================================== -// render 帮助方法 - -func (h *Handler) Render(ctx context.Context, w http.ResponseWriter, t templ.Component) { - if err := t.Render(ctx, w); err != nil { - h.Log.Error(err.Error(), err, - zap.String("templ render", fmt.Sprintf("%v", t)), - ) - } -} - -func (h *Handler) JSON(w http.ResponseWriter, data any) { - respond(w, data) -} - -func (h *Handler) JSONObj(w http.ResponseWriter, message string, data any) { - respond(w, Response{Success: true, Message: message, Data: data}) -} - -func (h *Handler) JSONOk(w http.ResponseWriter, message string) { - respond(w, Response{Success: true, Message: message}) -} - -func (h *Handler) JSONErr(w http.ResponseWriter, message string) { - respond(w, Response{Success: false, Message: message}) -} - -type Response struct { - Success bool `json:"success"` - Message string `json:"msg"` - Data any `json:"data"` -} - -type ResponseTree struct { - Status ResponseTreeStatus `json:"status"` - Data any `json:"data"` -} - -type ResponseTreeStatus struct { - Code int `json:"code"` - Message string `json:"message"` -} - -type ResponseList struct { - Code int `json:"code"` - Message string `json:"msg"` - Count int64 `json:"count"` - Data any `json:"data"` -} - -func respond(w http.ResponseWriter, data any) { - v, err := json.Marshal(data) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - w.Header().Set("Content-Type", "application/json; charset=utf-8") - w.WriteHeader(http.StatusOK) - _, err = w.Write(v) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } -} diff --git a/internal/erpserver/handler/route.go b/internal/erpserver/handler/route.go new file mode 100644 index 0000000..73c54eb --- /dev/null +++ b/internal/erpserver/handler/route.go @@ -0,0 +1,156 @@ +package handler + +import ( + "net/http" + + "management/assets" + "management/internal/erpserver/handler/captcha" + "management/internal/erpserver/handler/system/audit" + "management/internal/erpserver/handler/system/auth" + configapp "management/internal/erpserver/handler/system/config" + "management/internal/erpserver/handler/system/department" + "management/internal/erpserver/handler/system/home" + "management/internal/erpserver/handler/system/loginlog" + "management/internal/erpserver/handler/system/menu" + "management/internal/erpserver/handler/system/role" + "management/internal/erpserver/handler/system/user" + "management/internal/erpserver/handler/upload" + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/config" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" + "github.com/go-chi/chi/v5/middleware" +) + +type Config struct { + Conf *config.Config + Log *logger.Logger + Sm session.Manager + Render render.Renderer + CaptchaService v1.CaptchaService + UserService v1.UserService + RoleService v1.RoleService + DepartmentService v1.DepartmentService + MenuService v1.MenuService + ConfigService v1.ConfigService + AuditLogService v1.AuditLogService + LoginLogService v1.LoginLogService +} + +func WebApp(cfg Config) http.Handler { + app := chi.NewRouter() + + app.Use(middleware.RequestID) + app.Use(middleware.RealIP) + // r.Use(mid.Logger) + app.Use(middleware.Recoverer) + + staticServer := http.FileServer(http.FS(assets.FS)) + app.Handle("/assets/*", http.StripPrefix("/assets", staticServer)) + + uploadServer := http.FileServer(http.Dir("./public/")) + app.Handle("/public/*", http.StripPrefix("/public", uploadServer)) + + app.Group(func(r chi.Router) { + r.Use(mid.NoSurf) // CSRF + r.Use(mid.NoSurfContext) // CSRF Store Context + r.Use(mid.LoadSession(cfg.Sm)) // Session + + captcha.Routes(r, captcha.Config{ + Conf: cfg.Conf, + Render: cfg.Render, + CaptchaService: cfg.CaptchaService, + }) + + upload.Routes(r, upload.Config{ + Conf: cfg.Conf, + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + }) + + home.Routes(r, home.Config{ + Sm: cfg.Sm, + Render: cfg.Render, + UserService: cfg.UserService, + MenuService: cfg.MenuService, + LoginLogService: cfg.LoginLogService, + }) + + auth.Routes(r, auth.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + CaptchaService: cfg.CaptchaService, + UserService: cfg.UserService, + MenuService: cfg.MenuService, + }) + + r.Route("/system", func(r chi.Router) { + + r.Use(mid.Authorize(cfg.Sm, cfg.MenuService)) + + user.Routes(r, user.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + UserService: cfg.UserService, + RoleService: cfg.RoleService, + MenuService: cfg.MenuService, + DepartmentService: cfg.DepartmentService, + }) + + role.Routes(r, role.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + RoleService: cfg.RoleService, + MenuService: cfg.MenuService, + }) + + menu.Routes(r, menu.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + }) + + department.Routes(r, department.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + DepartmentService: cfg.DepartmentService, + }) + + configapp.Routes(r, configapp.Config{ + Log: cfg.Log, + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + ConfigService: cfg.ConfigService, + }) + + loginlog.Routes(r, loginlog.Config{ + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + LoginLogService: cfg.LoginLogService, + }) + + audit.Routes(r, audit.Config{ + Sm: cfg.Sm, + Render: cfg.Render, + MenuService: cfg.MenuService, + AuditLogService: cfg.AuditLogService, + }) + }) + }) + + return app +} diff --git a/internal/erpserver/handler/system/audit.go b/internal/erpserver/handler/system/audit/audit.go similarity index 64% rename from internal/erpserver/handler/system/audit.go rename to internal/erpserver/handler/system/audit/audit.go index 98f3934..88afbef 100644 --- a/internal/erpserver/handler/system/audit.go +++ b/internal/erpserver/handler/system/audit/audit.go @@ -1,32 +1,32 @@ -package system +package audit import ( "net/http" - "management/internal/erpserver/handler" "management/internal/erpserver/model/dto" v1 "management/internal/erpserver/service/v1" "management/internal/erpserver/templ/system/auditlog" "management/internal/pkg/convertor" + "management/internal/pkg/render" ) -type AuditHandler struct { - *handler.Handler +type App struct { + render render.Renderer auditLogService v1.AuditLogService } -func NewAuditHandler(handler *handler.Handler, auditLogService v1.AuditLogService) *AuditHandler { - return &AuditHandler{ - Handler: handler, +func NewApp(render render.Renderer, auditLogService v1.AuditLogService) *App { + return &App{ + render: render, auditLogService: auditLogService, } } -func (h *AuditHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, auditlog.List(ctx)) + a.render.Render(ctx, w, auditlog.List(ctx)) case http.MethodPost: var q dto.SearchDto q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) @@ -34,19 +34,19 @@ func (h *AuditHandler) List(w http.ResponseWriter, r *http.Request) { q.SearchEmail = r.PostFormValue("email") q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) - res, count, err := h.auditLogService.List(r.Context(), q) + res, count, err := a.auditLogService.List(r.Context(), q) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: count, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } diff --git a/internal/erpserver/handler/system/audit/route.go b/internal/erpserver/handler/system/audit/route.go new file mode 100644 index 0000000..7e2d7e8 --- /dev/null +++ b/internal/erpserver/handler/system/audit/route.go @@ -0,0 +1,25 @@ +package audit + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/go-chi/chi/v5" +) + +type Config struct { + Sm session.Manager + Render render.Renderer + MenuService v1.MenuService + AuditLogService v1.AuditLogService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.AuditLogService) + + r.Route("/audit_log", func(r chi.Router) { + r.Get("/list", app.list) + r.Post("/list", app.list) + }) +} diff --git a/internal/erpserver/handler/system/auth/auth.go b/internal/erpserver/handler/system/auth/auth.go new file mode 100644 index 0000000..43f0998 --- /dev/null +++ b/internal/erpserver/handler/system/auth/auth.go @@ -0,0 +1,97 @@ +package auth + +import ( + "io" + "log" + "net/http" + + "management/internal/erpserver/model/form" + v1 "management/internal/erpserver/service/v1" + "management/internal/erpserver/templ/auth" + "management/internal/pkg/binding" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" +) + +type App struct { + log *logger.Logger + sm session.Manager + render render.Renderer + captchaService v1.CaptchaService + userService v1.UserService +} + +func NewApp( + log *logger.Logger, + sm session.Manager, + render render.Renderer, + captchaService v1.CaptchaService, + userService v1.UserService, +) *App { + return &App{ + log: log, + sm: sm, + render: render, + captchaService: captchaService, + userService: userService, + } +} + +func (a *App) login(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + switch r.Method { + case http.MethodGet: + u := mid.GetUser(ctx) + if u.ID > 0 { + if err := a.sm.RenewToken(ctx); err == nil { + http.Redirect(w, r, "/home.html", http.StatusFound) + return + } + } + + _ = a.sm.Destroy(ctx) + component := auth.Login(ctx) + a.render.Render(ctx, w, component) + case http.MethodPost: + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + a.log.Error(err.Error(), err) + } + }(r.Body) + var req form.Login + if err := binding.Form.Bind(r, &req); err != nil { + e := binding.ValidatorErrors(err) + a.render.JSONErr(w, e) + return + } + + if !a.captchaService.Verify(req.CaptchaID, req.Captcha, true) { + a.render.JSONErr(w, "验证码错误") + return + } + + req = req.SetAttributes(r) + err := a.userService.Login(ctx, &req) + if err != nil { + log.Println(err) + a.render.JSONErr(w, err.Error()) + return + } + + a.render.JSONOk(w, "login successfully") + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + } +} + +func (a *App) logout(w http.ResponseWriter, r *http.Request) { + err := a.sm.Destroy(r.Context()) + if err != nil { + a.log.Error(err.Error(), err) + } + http.Redirect(w, r, "/", http.StatusFound) +} diff --git a/internal/erpserver/handler/system/auth/route.go b/internal/erpserver/handler/system/auth/route.go new file mode 100644 index 0000000..569a179 --- /dev/null +++ b/internal/erpserver/handler/system/auth/route.go @@ -0,0 +1,29 @@ +package auth + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + CaptchaService v1.CaptchaService + UserService v1.UserService + MenuService v1.MenuService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Log, cfg.Sm, cfg.Render, cfg.CaptchaService, cfg.UserService) + + r.Get("/", app.login) + r.Post("/login", app.login) + r.With(mid.Authorize(cfg.Sm, cfg.MenuService)).Get("/logout", app.logout) + +} diff --git a/internal/erpserver/handler/system/config.go b/internal/erpserver/handler/system/config/config.go similarity index 52% rename from internal/erpserver/handler/system/config.go rename to internal/erpserver/handler/system/config/config.go index 418ce33..52b80f1 100644 --- a/internal/erpserver/handler/system/config.go +++ b/internal/erpserver/handler/system/config/config.go @@ -1,11 +1,10 @@ -package system +package config import ( "encoding/json" "net/http" "strings" - "management/internal/erpserver/handler" "management/internal/erpserver/model/dto" systemModel "management/internal/erpserver/model/system" "management/internal/erpserver/model/view" @@ -13,25 +12,26 @@ import ( "management/internal/erpserver/templ/system/config" "management/internal/pkg/convertor" "management/internal/pkg/database" + "management/internal/pkg/render" ) -type ConfigHandler struct { - *handler.Handler +type App struct { + render render.Renderer configService systemService.ConfigService } -func NewConfigHandler(handler *handler.Handler, configService systemService.ConfigService) *ConfigHandler { - return &ConfigHandler{ - Handler: handler, +func NewApp(render render.Renderer, configService systemService.ConfigService) *App { + return &App{ + render: render, configService: configService, } } -func (h *ConfigHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, config.List(ctx)) + a.render.Render(ctx, w, config.List(ctx)) case http.MethodPost: var q dto.SearchDto q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) @@ -39,54 +39,54 @@ func (h *ConfigHandler) List(w http.ResponseWriter, r *http.Request) { q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) ctx := r.Context() - res, count, err := h.configService.List(ctx, q) + res, count, err := a.configService.List(ctx, q) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: count, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) } } -func (h *ConfigHandler) Add(w http.ResponseWriter, r *http.Request) { +func (a *App) add(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - h.Render(ctx, w, config.Edit(ctx, &view.EditSysConfig{Config: &systemModel.Config{}})) + a.render.Render(ctx, w, config.Edit(ctx, &view.EditSysConfig{Config: &systemModel.Config{}})) } -func (h *ConfigHandler) Edit(w http.ResponseWriter, r *http.Request) { +func (a *App) edit(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() id := convertor.QueryInt[int32](vars, "id", 0) vm := &view.EditSysConfig{} if id > 0 { - if conf, err := h.configService.Get(r.Context(), id); err == nil { + if conf, err := a.configService.Get(r.Context(), id); err == nil { vm.Config = conf b, _ := json.Marshal(&conf.Value) vm.Result = string(b) } } - h.Render(ctx, w, config.Edit(ctx, vm)) + a.render.Render(ctx, w, config.Edit(ctx, vm)) } -func (h *ConfigHandler) Save(w http.ResponseWriter, r *http.Request) { +func (a *App) save(w http.ResponseWriter, r *http.Request) { id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) key := r.PostFormValue("Key") value := r.PostFormValue("Value") if len(key) == 0 { - h.JSONErr(w, "Key不能为空") + a.render.JSONErr(w, "Key不能为空") return } if len(value) == 0 { - h.JSONErr(w, "Value不能为空") + a.render.JSONErr(w, "Value不能为空") return } @@ -96,61 +96,61 @@ func (h *ConfigHandler) Save(w http.ResponseWriter, r *http.Request) { Key: key, Value: []byte(value), } - err := h.configService.Create(ctx, arg) + err := a.configService.Create(ctx, arg) if err != nil { if database.IsUniqueViolation(err) { - h.JSONErr(w, "数据已存在") + a.render.JSONErr(w, "数据已存在") return } - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "添加成功") + a.render.JSONOk(w, "添加成功") } else { - res, err := h.configService.Get(ctx, id) + res, err := a.configService.Get(ctx, id) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } res.Value = []byte(value) - err = h.configService.Update(ctx, res) + err = a.configService.Update(ctx, res) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "更新成功") + a.render.JSONOk(w, "更新成功") } } -func (h *ConfigHandler) RefreshCache(w http.ResponseWriter, r *http.Request) { +func (a *App) refreshCache(w http.ResponseWriter, r *http.Request) { key := r.FormValue("key") - err := h.configService.RefreshCache(r.Context(), strings.ToLower(key)) + err := a.configService.RefreshCache(r.Context(), strings.ToLower(key)) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "刷新成功") + a.render.JSONOk(w, "刷新成功") } -func (h *ConfigHandler) ResetPear(w http.ResponseWriter, r *http.Request) { - err := h.configService.ResetPear(r.Context()) +func (a *App) resetPear(w http.ResponseWriter, r *http.Request) { + err := a.configService.ResetPear(r.Context()) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "重置成功") + a.render.JSONOk(w, "重置成功") } -func (h *ConfigHandler) Pear(w http.ResponseWriter, r *http.Request) { - pear, err := h.configService.Pear(r.Context()) +func (a *App) pear(w http.ResponseWriter, r *http.Request) { + pear, err := a.configService.Pear(r.Context()) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } - h.JSON(w, pear) + a.render.JSON(w, pear) } diff --git a/internal/erpserver/handler/system/config/route.go b/internal/erpserver/handler/system/config/route.go new file mode 100644 index 0000000..7ca2f31 --- /dev/null +++ b/internal/erpserver/handler/system/config/route.go @@ -0,0 +1,35 @@ +package config + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + MenuService v1.MenuService + ConfigService v1.ConfigService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.ConfigService) + + r.Get("/pear.json", app.pear) + r.Route("/config", func(r chi.Router) { + r.Use(mid.Audit(cfg.Sm, cfg.Log)) + r.Get("/list", app.list) + r.Post("/list", app.list) + r.Get("/add", app.add) + r.Get("/edit", app.edit) + r.Post("/save", app.save) + r.Post("/refresh_cache", app.refreshCache) + r.Post("/reset_pear", app.resetPear) + }) +} diff --git a/internal/erpserver/handler/system/department.go b/internal/erpserver/handler/system/department/department.go similarity index 51% rename from internal/erpserver/handler/system/department.go rename to internal/erpserver/handler/system/department/department.go index fea7cf8..bfa05fe 100644 --- a/internal/erpserver/handler/system/department.go +++ b/internal/erpserver/handler/system/department/department.go @@ -1,9 +1,8 @@ -package system +package department import ( "net/http" - "management/internal/erpserver/handler" "management/internal/erpserver/model/dto" "management/internal/erpserver/model/form" systemmodel "management/internal/erpserver/model/system" @@ -11,25 +10,26 @@ import ( "management/internal/erpserver/templ/system/department" "management/internal/pkg/binding" "management/internal/pkg/convertor" + "management/internal/pkg/render" ) -type DepartmentHandler struct { - *handler.Handler +type App struct { + render render.Renderer departmentService v1.DepartmentService } -func NewDepartmentHandler(handler *handler.Handler, departmentService v1.DepartmentService) *DepartmentHandler { - return &DepartmentHandler{ - Handler: handler, +func NewApp(render render.Renderer, departmentService v1.DepartmentService) *App { + return &App{ + render: render, departmentService: departmentService, } } -func (h *DepartmentHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, department.List(ctx)) + a.render.Render(ctx, w, department.List(ctx)) case http.MethodPost: var q dto.SearchDto q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) @@ -39,114 +39,114 @@ func (h *DepartmentHandler) List(w http.ResponseWriter, r *http.Request) { q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0) q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) - res, count, err := h.departmentService.List(r.Context(), q) + res, count, err := a.departmentService.List(r.Context(), q) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: count, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } } -func (h *DepartmentHandler) Add(w http.ResponseWriter, r *http.Request) { +func (a *App) add(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - h.Render(ctx, w, department.Edit(ctx, &systemmodel.Department{Sort: 6666})) + a.render.Render(ctx, w, department.Edit(ctx, &systemmodel.Department{Sort: 6666})) } -func (h *DepartmentHandler) AddChildren(w http.ResponseWriter, r *http.Request) { +func (a *App) addChildren(w http.ResponseWriter, r *http.Request) { vars := r.URL.Query() parentID := convertor.QueryInt[int32](vars, "parentID", 0) vm := &systemmodel.Department{ParentID: parentID, Sort: 6666} ctx := r.Context() - h.Render(ctx, w, department.Edit(ctx, vm)) + a.render.Render(ctx, w, department.Edit(ctx, vm)) } -func (h *DepartmentHandler) Edit(w http.ResponseWriter, r *http.Request) { +func (a *App) edit(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() id := convertor.QueryInt[int32](vars, "id", 0) vm := &systemmodel.Department{Sort: 6666} if id > 0 { - vm, _ = h.departmentService.Get(r.Context(), id) + vm, _ = a.departmentService.Get(r.Context(), id) } - h.Render(ctx, w, department.Edit(ctx, vm)) + a.render.Render(ctx, w, department.Edit(ctx, vm)) } -func (h *DepartmentHandler) Save(w http.ResponseWriter, r *http.Request) { +func (a *App) save(w http.ResponseWriter, r *http.Request) { var req form.Department if err := binding.Form.Bind(r, &req); err != nil { - h.JSONErr(w, binding.ValidatorErrors(err)) + a.render.JSONErr(w, binding.ValidatorErrors(err)) return } ctx := r.Context() if *req.ID == 0 { - err := h.departmentService.Create(ctx, &req) + err := a.departmentService.Create(ctx, &req) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "添加成功") + a.render.JSONOk(w, "添加成功") } else { - err := h.departmentService.Update(ctx, &req) + err := a.departmentService.Update(ctx, &req) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "更新成功") + a.render.JSONOk(w, "更新成功") } } -func (h *DepartmentHandler) Data(w http.ResponseWriter, r *http.Request) { +func (a *App) data(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() t := vars.Get("type") if t == "tree" { - res, err := h.departmentService.Tree(ctx, 0) + res, err := a.departmentService.Tree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) } else if t == "xm_select_tree" { - res, err := h.departmentService.XmSelectTree(ctx, 0) + res, err := a.departmentService.XmSelectTree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) } } -func (h *DepartmentHandler) RefreshCache(w http.ResponseWriter, r *http.Request) { - err := h.departmentService.RefreshCache(r.Context()) +func (a *App) refreshCache(w http.ResponseWriter, r *http.Request) { + err := a.departmentService.RefreshCache(r.Context()) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "缓存刷新成功") + a.render.JSONOk(w, "缓存刷新成功") } -func (h *DepartmentHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) { +func (a *App) rebuildParentPath(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - err := h.departmentService.RebuildParentPath(ctx) + err := a.departmentService.RebuildParentPath(ctx) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "重建成功") + a.render.JSONOk(w, "重建成功") } diff --git a/internal/erpserver/handler/system/department/route.go b/internal/erpserver/handler/system/department/route.go new file mode 100644 index 0000000..6b7ba0d --- /dev/null +++ b/internal/erpserver/handler/system/department/route.go @@ -0,0 +1,36 @@ +package department + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + MenuService v1.MenuService + DepartmentService v1.DepartmentService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.DepartmentService) + + r.Route("/department", func(r chi.Router) { + r.Use(mid.Audit(cfg.Sm, cfg.Log)) + r.Get("/list", app.list) + r.Post("/list", app.list) + r.Get("/add", app.add) + r.Get("/add_children", app.addChildren) + r.Get("/edit", app.edit) + r.Post("/save", app.save) + r.Post("/data", app.data) + r.Post("/refresh_cache", app.refreshCache) + r.Post("/rebuild_parent_path", app.rebuildParentPath) + }) +} diff --git a/internal/erpserver/handler/system/home.go b/internal/erpserver/handler/system/home.go deleted file mode 100644 index 6cdef70..0000000 --- a/internal/erpserver/handler/system/home.go +++ /dev/null @@ -1,41 +0,0 @@ -package system - -import ( - "net/http" - - "management/internal/erpserver/handler" - v1 "management/internal/erpserver/service/v1" - "management/internal/erpserver/templ/home" -) - -type HomeHandler struct { - *handler.Handler - userService v1.UserService - loginLogService v1.LoginLogService -} - -func NewHomeHandler( - handler *handler.Handler, - userService v1.UserService, - loginLogService v1.LoginLogService, -) *HomeHandler { - return &HomeHandler{ - Handler: handler, - userService: userService, - loginLogService: loginLogService, - } -} - -func (h *HomeHandler) Home(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - h.Render(ctx, w, home.Home(ctx)) -} - -func (h *HomeHandler) Dashboard(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - auth := h.AuthUser(ctx) - //user, _ := h.userService.Get(ctx, auth.ID) - lt, _ := h.loginLogService.LoginTime(ctx, auth.Email) - c := h.loginLogService.LoginCount(ctx, auth.Email) - h.Render(ctx, w, home.Dashboard(ctx, int(c), lt.ThisLoginTime, lt.LastLoginTime)) -} diff --git a/internal/erpserver/handler/system/home/home.go b/internal/erpserver/handler/system/home/home.go new file mode 100644 index 0000000..371e8e7 --- /dev/null +++ b/internal/erpserver/handler/system/home/home.go @@ -0,0 +1,44 @@ +package home + +import ( + "net/http" + + v1 "management/internal/erpserver/service/v1" + "management/internal/erpserver/templ/home" + "management/internal/pkg/mid" + "management/internal/pkg/render" +) + +type App struct { + render render.Renderer + userService v1.UserService + menuService v1.MenuService + loginLogService v1.LoginLogService +} + +func NewApp( + render render.Renderer, + userService v1.UserService, + menuService v1.MenuService, + loginLogService v1.LoginLogService, +) *App { + return &App{ + render: render, + userService: userService, + menuService: menuService, + loginLogService: loginLogService, + } +} + +func (a *App) home(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + a.render.Render(ctx, w, home.Home(ctx)) +} + +func (a *App) dashboard(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + auth := mid.GetUser(ctx) + lt, _ := a.loginLogService.LoginTime(ctx, auth.Email) + c := a.loginLogService.LoginCount(ctx, auth.Email) + a.render.Render(ctx, w, home.Dashboard(ctx, int(c), lt.ThisLoginTime, lt.LastLoginTime)) +} diff --git a/internal/erpserver/handler/system/home/route.go b/internal/erpserver/handler/system/home/route.go new file mode 100644 index 0000000..d9ba1b9 --- /dev/null +++ b/internal/erpserver/handler/system/home/route.go @@ -0,0 +1,25 @@ +package home + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/go-chi/chi/v5" +) + +type Config struct { + Sm session.Manager + Render render.Renderer + UserService v1.UserService + MenuService v1.MenuService + LoginLogService v1.LoginLogService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.UserService, cfg.MenuService, cfg.LoginLogService) + + r.With(mid.Authorize(cfg.Sm, cfg.MenuService)).Get("/home.html", app.home) + r.With(mid.Authorize(cfg.Sm, cfg.MenuService)).Get("/dashboard", app.dashboard) +} diff --git a/internal/erpserver/handler/system/login_log.go b/internal/erpserver/handler/system/loginlog/login_log.go similarity index 63% rename from internal/erpserver/handler/system/login_log.go rename to internal/erpserver/handler/system/loginlog/login_log.go index e4fe03d..1ab7725 100644 --- a/internal/erpserver/handler/system/login_log.go +++ b/internal/erpserver/handler/system/loginlog/login_log.go @@ -1,51 +1,51 @@ -package system +package loginlog import ( "net/http" - "management/internal/erpserver/handler" "management/internal/erpserver/model/dto" v1 "management/internal/erpserver/service/v1" "management/internal/erpserver/templ/system/loginlog" "management/internal/pkg/convertor" + "management/internal/pkg/render" ) -type LoginLogHandler struct { - *handler.Handler +type App struct { + render render.Renderer loginLogService v1.LoginLogService } -func NewLoginLogHandler(handler *handler.Handler, loginLogService v1.LoginLogService) *LoginLogHandler { - return &LoginLogHandler{ - Handler: handler, +func NewApp(render render.Renderer, loginLogService v1.LoginLogService) *App { + return &App{ + render: render, loginLogService: loginLogService, } } -func (h *LoginLogHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, loginlog.List(ctx)) + a.render.Render(ctx, w, loginlog.List(ctx)) case http.MethodPost: var q dto.SearchDto q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) q.SearchEmail = r.PostFormValue("email") q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) - res, count, err := h.loginLogService.List(r.Context(), q) + res, count, err := a.loginLogService.List(r.Context(), q) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: count, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } diff --git a/internal/erpserver/handler/system/loginlog/route.go b/internal/erpserver/handler/system/loginlog/route.go new file mode 100644 index 0000000..376fb25 --- /dev/null +++ b/internal/erpserver/handler/system/loginlog/route.go @@ -0,0 +1,25 @@ +package loginlog + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/go-chi/chi/v5" +) + +type Config struct { + Sm session.Manager + Render render.Renderer + MenuService v1.MenuService + LoginLogService v1.LoginLogService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.LoginLogService) + + r.Route("/login_log", func(r chi.Router) { + r.Get("/list", app.list) + r.Post("/list", app.list) + }) +} diff --git a/internal/erpserver/handler/system/menu.go b/internal/erpserver/handler/system/menu/menu.go similarity index 60% rename from internal/erpserver/handler/system/menu.go rename to internal/erpserver/handler/system/menu/menu.go index ff2af43..f303308 100644 --- a/internal/erpserver/handler/system/menu.go +++ b/internal/erpserver/handler/system/menu/menu.go @@ -1,4 +1,4 @@ -package system +package menu import ( "net/http" @@ -6,77 +6,78 @@ import ( "strings" "time" - "management/internal/erpserver/handler" systemmodel "management/internal/erpserver/model/system" v1 "management/internal/erpserver/service/v1" "management/internal/erpserver/templ/system/menu" "management/internal/pkg/convertor" "management/internal/pkg/database" + "management/internal/pkg/mid" + "management/internal/pkg/render" "github.com/google/uuid" ) const style = "layui-btn-primary layui-btn-sm" -type MenuHandler struct { - *handler.Handler +type App struct { + render render.Renderer menuService v1.MenuService } -func NewMenuHandler(handler *handler.Handler, menuService v1.MenuService) *MenuHandler { - return &MenuHandler{ - Handler: handler, +func NewApp(render render.Renderer, menuService v1.MenuService) *App { + return &App{ + render: render, menuService: menuService, } } -func (h *MenuHandler) Menus(w http.ResponseWriter, r *http.Request) { +func (a *App) menus(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - user := h.AuthUser(ctx) - menus, err := h.menuService.OwerMenus(ctx, user.RoleID) + user := mid.GetUser(ctx) + menus, err := a.menuService.OwerMenus(ctx, user.RoleID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, menus) + a.render.JSON(w, menus) } -func (h *MenuHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, menu.List(ctx)) + a.render.Render(ctx, w, menu.List(ctx)) case http.MethodPost: - res, err := h.menuService.ListMenuTree(r.Context()) + res, err := a.menuService.ListMenuTree(r.Context()) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: 0, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: - h.JSONErr(w, "method not allowed") + a.render.JSONErr(w, "method not allowed") } } -func (h *MenuHandler) Add(w http.ResponseWriter, r *http.Request) { +func (a *App) add(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - h.Render(ctx, w, menu.Edit(ctx, &systemmodel.Menu{Style: style, Visible: true, Sort: 6666})) + a.render.Render(ctx, w, menu.Edit(ctx, &systemmodel.Menu{Style: style, Visible: true, Sort: 6666})) } -func (h *MenuHandler) AddChildren(w http.ResponseWriter, r *http.Request) { +func (a *App) addChildren(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() parentID := convertor.QueryInt[int32](vars, "parentID", 0) vm := &systemmodel.Menu{ParentID: parentID, Style: style, Visible: true, Sort: 6666} - parent, err := h.menuService.Get(ctx, parentID) + parent, err := a.menuService.Get(ctx, parentID) if err == nil { if parent.Type == "node" { vm.Type = "menu" @@ -84,21 +85,21 @@ func (h *MenuHandler) AddChildren(w http.ResponseWriter, r *http.Request) { vm.Type = "btn" } } - h.Render(ctx, w, menu.Edit(ctx, vm)) + a.render.Render(ctx, w, menu.Edit(ctx, vm)) } -func (h *MenuHandler) Edit(w http.ResponseWriter, r *http.Request) { +func (a *App) edit(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() id := convertor.QueryInt[int32](vars, "id", 0) vm := &systemmodel.Menu{Style: style, Sort: 6666} if id > 0 { - vm, _ = h.menuService.Get(r.Context(), id) + vm, _ = a.menuService.Get(r.Context(), id) } - h.Render(ctx, w, menu.Edit(ctx, vm)) + a.render.Render(ctx, w, menu.Edit(ctx, vm)) } -func (h *MenuHandler) Save(w http.ResponseWriter, r *http.Request) { +func (a *App) save(w http.ResponseWriter, r *http.Request) { id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) name := r.PostFormValue("Name") displayName := r.PostFormValue("DisplayName") @@ -122,9 +123,9 @@ func (h *MenuHandler) Save(w http.ResponseWriter, r *http.Request) { parentPath := "" if parentID > 0 { - parent, err := h.menuService.Get(ctx, parentID) + parent, err := a.menuService.Get(ctx, parentID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } parentPath = parent.ParentPath + "," + strconv.Itoa(int(parentID)) + "," @@ -148,21 +149,21 @@ func (h *MenuHandler) Save(w http.ResponseWriter, r *http.Request) { CreatedAt: time.Now(), UpdatedAt: time.Now(), } - err := h.menuService.Create(ctx, arg) + err := a.menuService.Create(ctx, arg) if err != nil { if database.IsUniqueViolation(err) { - h.JSONErr(w, "菜单已存在") + a.render.JSONErr(w, "菜单已存在") return } - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "添加成功") + a.render.JSONOk(w, "添加成功") } else { - res, err := h.menuService.Get(ctx, id) + res, err := a.menuService.Get(ctx, id) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } @@ -179,48 +180,48 @@ func (h *MenuHandler) Save(w http.ResponseWriter, r *http.Request) { res.Status = status res.Sort = sort res.UpdatedAt = time.Now() - err = h.menuService.Update(ctx, res) + err = a.menuService.Update(ctx, res) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "更新成功") + a.render.JSONOk(w, "更新成功") } } -func (h *MenuHandler) Data(w http.ResponseWriter, r *http.Request) { +func (a *App) data(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() t := vars.Get("type") if t == "tree" { - res, err := h.menuService.Tree(ctx, 0) + res, err := a.menuService.Tree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) return } else if t == "xm_select_tree" { - res, err := h.menuService.XmSelectTree(ctx, 0) + res, err := a.menuService.XmSelectTree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) return } - h.JSON(w, nil) + a.render.JSON(w, nil) } -func (h *MenuHandler) RefreshCache(w http.ResponseWriter, r *http.Request) { - err := h.menuService.RefreshCache(r.Context()) +func (a *App) refreshCache(w http.ResponseWriter, r *http.Request) { + err := a.menuService.RefreshCache(r.Context()) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "缓存刷新成功") + a.render.JSONOk(w, "缓存刷新成功") } diff --git a/internal/erpserver/handler/system/menu/route.go b/internal/erpserver/handler/system/menu/route.go new file mode 100644 index 0000000..b36a383 --- /dev/null +++ b/internal/erpserver/handler/system/menu/route.go @@ -0,0 +1,35 @@ +package menu + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + MenuService v1.MenuService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.MenuService) + + r.Get("/menus", app.menus) + r.Route("/menu", func(r chi.Router) { + r.Use(mid.Audit(cfg.Sm, cfg.Log)) + r.Get("/list", app.list) + r.Post("/list", app.list) + r.Get("/add", app.add) + r.Get("/add_children", app.addChildren) + r.Get("/edit", app.edit) + r.Post("/save", app.save) + r.Post("/data", app.data) + r.Post("/refresh_cache", app.refreshCache) + }) +} diff --git a/internal/erpserver/handler/system/role.go b/internal/erpserver/handler/system/role/role.go similarity index 53% rename from internal/erpserver/handler/system/role.go rename to internal/erpserver/handler/system/role/role.go index 534ae69..180c678 100644 --- a/internal/erpserver/handler/system/role.go +++ b/internal/erpserver/handler/system/role/role.go @@ -1,10 +1,9 @@ -package system +package role import ( "net/http" "strings" - "management/internal/erpserver/handler" "management/internal/erpserver/model/dto" "management/internal/erpserver/model/form" "management/internal/erpserver/model/system" @@ -13,27 +12,28 @@ import ( "management/internal/erpserver/templ/system/role" "management/internal/pkg/binding" "management/internal/pkg/convertor" + "management/internal/pkg/render" ) -type RoleHandler struct { - *handler.Handler +type App struct { + render render.Renderer roleService v1.RoleService menuService v1.MenuService } -func NewRoleHandler(handler *handler.Handler, roleService v1.RoleService, menuService v1.MenuService) *RoleHandler { - return &RoleHandler{ - Handler: handler, +func NewApp(render render.Renderer, roleService v1.RoleService, menuService v1.MenuService) *App { + return &App{ + render: render, roleService: roleService, menuService: menuService, } } -func (h *RoleHandler) List(w http.ResponseWriter, r *http.Request) { +func (a *App) list(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: ctx := r.Context() - h.Render(ctx, w, role.List(ctx)) + a.render.Render(ctx, w, role.List(ctx)) case http.MethodPost: var q dto.SearchDto q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) @@ -43,155 +43,155 @@ func (h *RoleHandler) List(w http.ResponseWriter, r *http.Request) { q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0) q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) - res, count, err := h.roleService.List(r.Context(), q) + res, count, err := a.roleService.List(r.Context(), q) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - data := handler.ResponseList{ + data := render.ResponseList{ Code: 0, Message: "ok", Count: count, Data: res, } - h.JSON(w, data) + a.render.JSON(w, data) default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } } -func (h *RoleHandler) Add(w http.ResponseWriter, r *http.Request) { +func (a *App) add(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - h.Render(ctx, w, role.Edit(ctx, &system.Role{Sort: 6666})) + a.render.Render(ctx, w, role.Edit(ctx, &system.Role{Sort: 6666})) } -func (h *RoleHandler) AddChildren(w http.ResponseWriter, r *http.Request) { +func (a *App) addChildren(w http.ResponseWriter, r *http.Request) { vars := r.URL.Query() parentID := convertor.QueryInt[int32](vars, "parentID", 0) vm := &system.Role{ParentID: parentID, Sort: 6666} ctx := r.Context() - h.Render(ctx, w, role.Edit(ctx, vm)) + a.render.Render(ctx, w, role.Edit(ctx, vm)) } -func (h *RoleHandler) Edit(w http.ResponseWriter, r *http.Request) { +func (a *App) edit(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() id := convertor.QueryInt[int32](vars, "id", 0) vm := &system.Role{Sort: 6666} if id > 0 { - vm, _ = h.roleService.Get(ctx, id) + vm, _ = a.roleService.Get(ctx, id) } - h.Render(ctx, w, role.Edit(ctx, vm)) + a.render.Render(ctx, w, role.Edit(ctx, vm)) } -func (h *RoleHandler) Save(w http.ResponseWriter, r *http.Request) { +func (a *App) save(w http.ResponseWriter, r *http.Request) { var req form.Role if err := binding.Form.Bind(r, &req); err != nil { - h.JSONErr(w, binding.ValidatorErrors(err)) + a.render.JSONErr(w, binding.ValidatorErrors(err)) return } ctx := r.Context() if *req.ID == 0 { - err := h.roleService.Create(ctx, &req) + err := a.roleService.Create(ctx, &req) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "添加成功") + a.render.JSONOk(w, "添加成功") } else { - err := h.roleService.Update(ctx, &req) + err := a.roleService.Update(ctx, &req) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "更新成功") + a.render.JSONOk(w, "更新成功") } } -func (h *RoleHandler) Data(w http.ResponseWriter, r *http.Request) { +func (a *App) data(w http.ResponseWriter, r *http.Request) { ctx := r.Context() vars := r.URL.Query() t := vars.Get("type") if t == "tree" { - res, err := h.roleService.Tree(ctx, 0) + res, err := a.roleService.Tree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) } else if t == "xm_select_tree" { - res, err := h.roleService.XmSelectTree(ctx, 0) + res, err := a.roleService.XmSelectTree(ctx, 0) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSON(w, res) + a.render.JSON(w, res) } } -func (h *RoleHandler) RefreshCache(w http.ResponseWriter, r *http.Request) { - err := h.roleService.RefreshCache(r.Context()) +func (a *App) refreshCache(w http.ResponseWriter, r *http.Request) { + err := a.roleService.RefreshCache(r.Context()) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "缓存刷新成功") + a.render.JSONOk(w, "缓存刷新成功") } -func (h *RoleHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) { +func (a *App) rebuildParentPath(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - err := h.roleService.RebuildParentPath(ctx) + err := a.roleService.RebuildParentPath(ctx) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "重建成功") + a.render.JSONOk(w, "重建成功") } -func (h *RoleHandler) RefreshRoleMenus(w http.ResponseWriter, r *http.Request) { +func (a *App) refreshRoleMenus(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // 获取需要刷新的角色ID roleID := convertor.ConvertInt[int32](r.PostFormValue("roleID"), 0) - roleModel, err := h.roleService.Get(ctx, roleID) + roleModel, err := a.roleService.Get(ctx, roleID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } if roleModel == nil { - h.JSONErr(w, "角色不存在") + a.render.JSONErr(w, "角色不存在") return } // 刷新角色菜单 (角色所拥有的菜单集合) - _, err = h.menuService.SetListByRoleID(ctx, roleModel.ID) + _, err = a.menuService.SetListByRoleID(ctx, roleModel.ID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } // 刷新角色菜单 (角色所拥有的菜单集合) - _, err = h.menuService.SetListByRoleIDToMap(ctx, roleModel.ID) + _, err = a.menuService.SetListByRoleIDToMap(ctx, roleModel.ID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } // 刷新角色菜单树 (pear admin layui 使用的格式) - _, err = h.menuService.SetOwerMenus(ctx, roleModel.ID) + _, err = a.menuService.SetOwerMenus(ctx, roleModel.ID) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "刷新成功") + a.render.JSONOk(w, "刷新成功") } -func (h *RoleHandler) SetMenu(w http.ResponseWriter, r *http.Request) { +func (a *App) setMenu(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: vars := r.URL.Query() @@ -203,33 +203,33 @@ func (h *RoleHandler) SetMenu(w http.ResponseWriter, r *http.Request) { ctx := r.Context() if id > 0 { var err error - vm.Role, err = h.roleService.Get(ctx, id) + vm.Role, err = a.roleService.Get(ctx, id) if err == nil { - vm.Menus, _ = h.menuService.MenuViewData(ctx, vm.Role.ID) + vm.Menus, _ = a.menuService.MenuViewData(ctx, vm.Role.ID) } } - h.Render(ctx, w, role.SetMenu(ctx, vm)) + a.render.Render(ctx, w, role.SetMenu(ctx, vm)) case http.MethodPost: ctx := r.Context() id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) if id == 0 { - h.JSONErr(w, "角色异常, 请刷新重试") + a.render.JSONErr(w, "角色异常, 请刷新重试") return } - roleModel, err := h.roleService.Get(ctx, id) + roleModel, err := a.roleService.Get(ctx, id) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } menus := r.PostFormValue("roleMenu") if len(menus) == 0 { - h.JSONErr(w, "请选择菜单") + a.render.JSONErr(w, "请选择菜单") return } menuArr := strings.Split(menus, ",") if len(menuArr) == 0 { - h.JSONErr(w, "请选择菜单") + a.render.JSONErr(w, "请选择菜单") return } @@ -237,9 +237,9 @@ func (h *RoleHandler) SetMenu(w http.ResponseWriter, r *http.Request) { for _, v := range menuArr { menuID := convertor.ConvertInt(v, 0) if menuID > 0 { - menu, err := h.menuService.Get(ctx, int32(menuID)) + menu, err := a.menuService.Get(ctx, int32(menuID)) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } @@ -251,17 +251,17 @@ func (h *RoleHandler) SetMenu(w http.ResponseWriter, r *http.Request) { } if len(rms) == 0 { - h.JSONErr(w, "请选择正确的菜单") + a.render.JSONErr(w, "请选择正确的菜单") return } - err = h.menuService.SetRoleMenu(ctx, id, rms) + err = a.menuService.SetRoleMenu(ctx, id, rms) if err != nil { - h.JSONErr(w, err.Error()) + a.render.JSONErr(w, err.Error()) return } - h.JSONOk(w, "设置成功") + a.render.JSONOk(w, "设置成功") default: http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } diff --git a/internal/erpserver/handler/system/role/route.go b/internal/erpserver/handler/system/role/route.go new file mode 100644 index 0000000..6edd080 --- /dev/null +++ b/internal/erpserver/handler/system/role/route.go @@ -0,0 +1,39 @@ +package role + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + RoleService v1.RoleService + MenuService v1.MenuService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp(cfg.Render, cfg.RoleService, cfg.MenuService) + + r.Route("/role", func(r chi.Router) { + r.Use(mid.Audit(cfg.Sm, cfg.Log)) + r.Get("/list", app.list) + r.Post("/list", app.list) + r.Get("/add", app.add) + r.Get("/add_children", app.addChildren) + r.Get("/edit", app.edit) + r.Post("/save", app.save) + r.Post("/data", app.data) + r.Post("/refresh_cache", app.refreshCache) + r.Post("/rebuild_parent_path", app.rebuildParentPath) + r.Post("/refresh_role_menus", app.refreshRoleMenus) + r.Get("/set_menu", app.setMenu) + r.Post("/set_menu", app.setMenu) + }) +} diff --git a/internal/erpserver/handler/system/router.go b/internal/erpserver/handler/system/router.go deleted file mode 100644 index 523604f..0000000 --- a/internal/erpserver/handler/system/router.go +++ /dev/null @@ -1,145 +0,0 @@ -package system - -// -//import ( -// v1 "management/internal/erpserver/service/v1" -// mi "management/internal/pkg/mid" -// "management/internal/pkg/session" -// -// "github.com/go-chi/chi/v5" -//) -// -//type HandlerGroup struct { -// sm session.Manager -// menuService v1.MenuService -// HomeHandler *HomeHandler -// ConfigHandler *ConfigHandler -// UserHandler *UserHandler -// LoginLogHandler *LoginLogHandler -// AuditHandler *AuditHandler -// MenuHandler *MenuHandler -// RoleHandler *RoleHandler -// DepartmentHandler *DepartmentHandler -//} -// -//func NewHandlerGroup( -// sm session.Manager, -// menuService v1.MenuService, -// homeHandler *HomeHandler, -// configHandler *ConfigHandler, -// userHandler *UserHandler, -// loginLogHandler *LoginLogHandler, -// auditHandler *AuditHandler, -// menuHandler *MenuHandler, -// roleHandler *RoleHandler, -// departmentHandler *DepartmentHandler, -//) *HandlerGroup { -// return &HandlerGroup{ -// sm: sm, -// HomeHandler: homeHandler, -// ConfigHandler: configHandler, -// UserHandler: userHandler, -// LoginLogHandler: loginLogHandler, -// AuditHandler: auditHandler, -// MenuHandler: menuHandler, -// RoleHandler: roleHandler, -// DepartmentHandler: departmentHandler, -// } -//} -// -//func (g *HandlerGroup) Register(r chi.Router) { -// //r.Get("/captcha", g.CaptchaHandler.Captcha) -// //r.Post("/login", userHandler.Login) -// -// r.Get("/", g.UserHandler.Login) -// r.Group(func(r chi.Router) { -// r.Use(mi.Authorize(g.sm, menuService)) -// -// r.Get("/logout", userHandler.Logout) -// -// r.Get("/home.html", homeHandler.Home) -// r.Get("/dashboard", homeHandler.Dashboard) -// r.Get("/pear.json", configHandler.Pear) -// -// r.Route("/upload", func(r chi.Router) { -// r.Use(mi.Audit(sm, auditLogService, log)) -// r.Get("/img", uploadHandler.Img) -// r.Get("/file", uploadHandler.File) -// r.Get("/multi_files", uploadHandler.MultiFiles) -// }) -// -// r.Route("/system", func(r chi.Router) { -// r.Use(mi.Audit(sm, auditLogService, log)) -// -// r.Get("/menus", menuHandler.Menus) -// -// r.Route("/config", func(r chi.Router) { -// r.Get("/list", configHandler.List) -// r.Post("/list", configHandler.List) -// r.Get("/add", configHandler.Add) -// r.Get("/edit", configHandler.Edit) -// r.Post("/save", configHandler.Save) -// r.Post("/refresh_cache", configHandler.RefreshCache) -// r.Post("/reset_pear", configHandler.ResetPear) -// }) -// -// r.Route("/menu", func(r chi.Router) { -// r.Get("/list", menuHandler.List) -// r.Post("/list", menuHandler.List) -// r.Get("/add", menuHandler.Add) -// r.Get("/add_children", menuHandler.AddChildren) -// r.Get("/edit", menuHandler.Edit) -// r.Post("/save", menuHandler.Save) -// r.Post("/data", menuHandler.Data) -// r.Post("/refresh_cache", menuHandler.RefreshCache) -// }) -// -// r.Route("/department", func(r chi.Router) { -// r.Get("/list", departmentHandler.List) -// r.Post("/list", departmentHandler.List) -// r.Get("/add", departmentHandler.Add) -// r.Get("/add_children", departmentHandler.AddChildren) -// r.Get("/edit", departmentHandler.Edit) -// r.Post("/save", departmentHandler.Save) -// r.Post("/data", departmentHandler.Data) -// r.Post("/refresh_cache", departmentHandler.RefreshCache) -// r.Post("/rebuild_parent_path", departmentHandler.RebuildParentPath) -// }) -// -// r.Route("/role", func(r chi.Router) { -// r.Get("/list", roleHandler.List) -// r.Post("/list", roleHandler.List) -// r.Get("/add", roleHandler.Add) -// r.Get("/add_children", roleHandler.AddChildren) -// r.Get("/edit", roleHandler.Edit) -// r.Post("/save", roleHandler.Save) -// r.Post("/data", roleHandler.Data) -// r.Post("/refresh_cache", roleHandler.RefreshCache) -// r.Post("/rebuild_parent_path", roleHandler.RebuildParentPath) -// r.Post("/refresh_role_menus", roleHandler.RefreshRoleMenus) -// r.Get("/set_menu", roleHandler.SetMenu) -// r.Post("/set_menu", roleHandler.SetMenu) -// }) -// -// r.Route("/user", func(r chi.Router) { -// r.Get("/list", userHandler.List) -// r.Post("/list", userHandler.List) -// r.Get("/add", userHandler.Add) -// r.Get("/edit", userHandler.Edit) -// r.Post("/save", userHandler.Save) -// r.Get("/profile", userHandler.Profile) -// r.Post("/data", userHandler.Data) -// }) -// -// r.Route("/login_log", func(r chi.Router) { -// r.Get("/list", loginLogHandler.List) -// r.Post("/list", loginLogHandler.List) -// }) -// -// r.Route("/audit_log", func(r chi.Router) { -// r.Get("/list", auditHandler.List) -// r.Post("/list", auditHandler.List) -// }) -// }) -// }) -//} diff --git a/internal/erpserver/handler/system/user.go b/internal/erpserver/handler/system/user.go deleted file mode 100644 index b42b06f..0000000 --- a/internal/erpserver/handler/system/user.go +++ /dev/null @@ -1,212 +0,0 @@ -package system - -import ( - "io" - "log" - "net/http" - - "management/internal/erpserver/handler" - "management/internal/erpserver/model/dto" - "management/internal/erpserver/model/form" - systemmodel "management/internal/erpserver/model/system" - v1 "management/internal/erpserver/service/v1" - "management/internal/erpserver/templ/auth" - "management/internal/erpserver/templ/system/user" - "management/internal/pkg/binding" - "management/internal/pkg/convertor" -) - -type UserHandler struct { - *handler.Handler - captchaService v1.CaptchaService - userService v1.UserService - roleService v1.RoleService - departmentService v1.DepartmentService -} - -func NewUserHandler( - handler *handler.Handler, - captchaService v1.CaptchaService, - userService v1.UserService, - roleService v1.RoleService, - departmentService v1.DepartmentService, -) *UserHandler { - return &UserHandler{ - Handler: handler, - captchaService: captchaService, - userService: userService, - roleService: roleService, - departmentService: departmentService, - } -} - -func (h *UserHandler) Add(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - h.Render(ctx, w, user.Edit(ctx, &systemmodel.User{HashedPassword: nil})) -} - -func (h *UserHandler) Edit(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - vars := r.URL.Query() - id := convertor.QueryInt[int32](vars, "id", 0) - vm := &systemmodel.User{} - if id > 0 { - if u, err := h.userService.Get(ctx, id); err == nil { - vm.HashedPassword = []byte("********") - vm = u - } - } - h.Render(ctx, w, user.Edit(ctx, vm)) -} - -func (h *UserHandler) Save(w http.ResponseWriter, r *http.Request) { - var req form.User - if err := binding.Form.Bind(r, &req); err != nil { - h.JSONErr(w, binding.ValidatorErrors(err)) - return - } - - ctx := r.Context() - if req.DepartmentID > 0 { - if _, err := h.departmentService.Get(ctx, req.DepartmentID); err != nil { - h.JSONErr(w, "部门数据错误") - return - } - } - if req.RoleID > 0 { - if _, err := h.roleService.Get(ctx, req.RoleID); err != nil { - h.JSONErr(w, "角色数据错误") - return - } - } - - if *req.ID == 0 { - err := h.userService.Create(ctx, &req) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - h.JSONOk(w, "添加成功") - } else { - err := h.userService.Update(ctx, &req) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - h.JSONOk(w, "更新成功") - } -} - -func (h *UserHandler) List(w http.ResponseWriter, r *http.Request) { - switch r.Method { - case http.MethodGet: - ctx := r.Context() - h.Render(ctx, w, user.List(ctx)) - case http.MethodPost: - var q dto.SearchDto - q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) - q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999) - q.SearchName = r.PostFormValue("name") - q.SearchEmail = r.PostFormValue("email") - q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0) - q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) - q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) - res, count, err := h.userService.List(r.Context(), q) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - data := handler.ResponseList{ - Code: 0, - Message: "ok", - Count: count, - Data: res, - } - h.JSON(w, data) - default: - http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) - } -} - -func (h *UserHandler) Profile(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - u := h.AuthUser(ctx) - vm, _ := h.userService.Get(ctx, u.ID) - h.Render(ctx, w, user.Profile(ctx, vm)) -} - -func (h *UserHandler) Data(w http.ResponseWriter, r *http.Request) { - vars := r.URL.Query() - t := vars.Get("type") - if t == "xm_select" { - res, err := h.userService.XmSelect(r.Context()) - if err != nil { - h.JSONErr(w, err.Error()) - return - } - - h.JSON(w, res) - return - } - - h.JSON(w, nil) -} - -func (h *UserHandler) Login(w http.ResponseWriter, r *http.Request) { - ctx := r.Context() - switch r.Method { - case http.MethodGet: - u := h.AuthUser(ctx) - if u.ID > 0 { - if err := h.RenewToken(ctx); err == nil { - http.Redirect(w, r, "/home.html", http.StatusFound) - return - } - } - - _ = h.Destroy(ctx) - component := auth.Login(ctx) - h.Render(ctx, w, component) - case http.MethodPost: - defer func(Body io.ReadCloser) { - err := Body.Close() - if err != nil { - h.Log.Error(err.Error(), err) - } - }(r.Body) - var req form.Login - if err := binding.Form.Bind(r, &req); err != nil { - e := binding.ValidatorErrors(err) - h.JSONErr(w, e) - return - } - - if !h.captchaService.Verify(req.CaptchaID, req.Captcha, true) { - h.JSONErr(w, "验证码错误") - return - } - - req = req.SetAttributes(r) - err := h.userService.Login(ctx, &req) - if err != nil { - log.Println(err) - h.JSONErr(w, err.Error()) - return - } - - h.JSONOk(w, "login successfully") - default: - http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) - } -} - -func (h *UserHandler) Logout(w http.ResponseWriter, r *http.Request) { - err := h.Destroy(r.Context()) - if err != nil { - h.Log.Error(err.Error(), err) - } - http.Redirect(w, r, "/", http.StatusFound) -} diff --git a/internal/erpserver/handler/system/user/route.go b/internal/erpserver/handler/system/user/route.go new file mode 100644 index 0000000..278e485 --- /dev/null +++ b/internal/erpserver/handler/system/user/route.go @@ -0,0 +1,43 @@ +package user + +import ( + v1 "management/internal/erpserver/service/v1" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" + "github.com/go-chi/chi/v5" +) + +type Config struct { + Log *logger.Logger + Sm session.Manager + Render render.Renderer + UserService v1.UserService + RoleService v1.RoleService + MenuService v1.MenuService + DepartmentService v1.DepartmentService +} + +func Routes(r chi.Router, cfg Config) { + app := NewApp( + cfg.Log, + cfg.Sm, + cfg.Render, + cfg.UserService, + cfg.RoleService, + cfg.DepartmentService, + ) + + r.Route("/user", func(r chi.Router) { + r.Use(mid.Audit(cfg.Sm, cfg.Log)) + r.Get("/list", app.list) + r.Post("/list", app.list) + r.Get("/add", app.add) + r.Get("/edit", app.edit) + r.Post("/save", app.save) + r.Get("/profile", app.profile) + r.Post("/data", app.data) + }) +} diff --git a/internal/erpserver/handler/system/user/user.go b/internal/erpserver/handler/system/user/user.go new file mode 100644 index 0000000..13b392b --- /dev/null +++ b/internal/erpserver/handler/system/user/user.go @@ -0,0 +1,160 @@ +package user + +import ( + "net/http" + + "management/internal/erpserver/model/dto" + "management/internal/erpserver/model/form" + systemmodel "management/internal/erpserver/model/system" + v1 "management/internal/erpserver/service/v1" + "management/internal/erpserver/templ/system/user" + "management/internal/pkg/binding" + "management/internal/pkg/convertor" + "management/internal/pkg/mid" + "management/internal/pkg/render" + "management/internal/pkg/session" + + "github.com/drhin/logger" +) + +type App struct { + log *logger.Logger + sm session.Manager + render render.Renderer + userService v1.UserService + roleService v1.RoleService + departmentService v1.DepartmentService +} + +func NewApp( + log *logger.Logger, + sm session.Manager, + render render.Renderer, + userService v1.UserService, + roleService v1.RoleService, + departmentService v1.DepartmentService, +) *App { + return &App{ + log: log, + sm: sm, + render: render, + userService: userService, + roleService: roleService, + departmentService: departmentService, + } +} + +func (a *App) add(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + a.render.Render(ctx, w, user.Edit(ctx, &systemmodel.User{HashedPassword: nil})) +} + +func (a *App) edit(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := r.URL.Query() + id := convertor.QueryInt[int32](vars, "id", 0) + vm := &systemmodel.User{} + if id > 0 { + if u, err := a.userService.Get(ctx, id); err == nil { + vm.HashedPassword = []byte("********") + vm = u + } + } + a.render.Render(ctx, w, user.Edit(ctx, vm)) +} + +func (a *App) save(w http.ResponseWriter, r *http.Request) { + var req form.User + if err := binding.Form.Bind(r, &req); err != nil { + a.render.JSONErr(w, binding.ValidatorErrors(err)) + return + } + + ctx := r.Context() + if req.DepartmentID > 0 { + if _, err := a.departmentService.Get(ctx, req.DepartmentID); err != nil { + a.render.JSONErr(w, "部门数据错误") + return + } + } + if req.RoleID > 0 { + if _, err := a.roleService.Get(ctx, req.RoleID); err != nil { + a.render.JSONErr(w, "角色数据错误") + return + } + } + + if *req.ID == 0 { + err := a.userService.Create(ctx, &req) + if err != nil { + a.render.JSONErr(w, err.Error()) + return + } + + a.render.JSONOk(w, "添加成功") + } else { + err := a.userService.Update(ctx, &req) + if err != nil { + a.render.JSONErr(w, err.Error()) + return + } + + a.render.JSONOk(w, "更新成功") + } +} + +func (a *App) list(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + ctx := r.Context() + a.render.Render(ctx, w, user.List(ctx)) + case http.MethodPost: + var q dto.SearchDto + q.SearchTimeBegin, q.SearchTimeEnd = convertor.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) + q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999) + q.SearchName = r.PostFormValue("name") + q.SearchEmail = r.PostFormValue("email") + q.SearchID = convertor.ConvertInt[int64](r.PostFormValue("id"), 0) + q.Page = convertor.ConvertInt(r.PostFormValue("page"), 1) + q.Rows = convertor.ConvertInt(r.PostFormValue("rows"), 10) + res, count, err := a.userService.List(r.Context(), q) + if err != nil { + a.render.JSONErr(w, err.Error()) + return + } + + data := render.ResponseList{ + Code: 0, + Message: "ok", + Count: count, + Data: res, + } + a.render.JSON(w, data) + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + } +} + +func (a *App) profile(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + u := mid.GetUser(ctx) + vm, _ := a.userService.Get(ctx, u.ID) + a.render.Render(ctx, w, user.Profile(ctx, vm)) +} + +func (a *App) data(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + t := vars.Get("type") + if t == "xm_select" { + res, err := a.userService.XmSelect(r.Context()) + if err != nil { + a.render.JSONErr(w, err.Error()) + return + } + + a.render.JSON(w, res) + return + } + + a.render.JSON(w, nil) +} diff --git a/internal/erpserver/http.go b/internal/erpserver/http.go deleted file mode 100644 index 17e187d..0000000 --- a/internal/erpserver/http.go +++ /dev/null @@ -1,150 +0,0 @@ -package erpserver - -import ( - "net/http" - - "management/assets" - "management/internal/erpserver/handler/common" - "management/internal/erpserver/handler/system" - v1 "management/internal/erpserver/service/v1" - mi "management/internal/pkg/mid" - "management/internal/pkg/session" - - "github.com/drhin/logger" - "github.com/go-chi/chi/v5" - "github.com/go-chi/chi/v5/middleware" -) - -func NewHTTPServer( - sm session.Manager, - log *logger.Logger, - menuService v1.MenuService, - auditLogService v1.AuditLogService, - captchaHandler *common.CaptchaHandler, - uploadHandler *common.UploadHandler, - configHandler *system.ConfigHandler, - homeHandler *system.HomeHandler, - userHandler *system.UserHandler, - loginLogHandler *system.LoginLogHandler, - auditHandler *system.AuditHandler, - menuHandler *system.MenuHandler, - roleHandler *system.RoleHandler, - departmentHandler *system.DepartmentHandler, -) *chi.Mux { - r := chi.NewRouter() - - r.Use(middleware.RequestID) - r.Use(middleware.RealIP) - // r.Use(mid.Logger) - r.Use(middleware.Recoverer) - - staticServer := http.FileServer(http.FS(assets.FS)) - r.Handle("/assets/*", http.StripPrefix("/assets", staticServer)) - - uploadServer := http.FileServer(http.Dir("./public/")) - r.Handle("/public/*", http.StripPrefix("/public", uploadServer)) - - r.Group(func(r chi.Router) { - r.Use(mi.NoSurf) // CSRF - r.Use(mi.NoSurfContext) // CSRF Store Context - r.Use(mi.LoadSession(sm)) // Session - - r.Get("/", userHandler.Login) - r.Get("/captcha", captchaHandler.Captcha) - r.Post("/login", userHandler.Login) - - r.Group(func(r chi.Router) { - r.Use(mi.Authorize(sm, menuService)) - - r.Get("/logout", userHandler.Logout) - - r.Get("/home.html", homeHandler.Home) - r.Get("/dashboard", homeHandler.Dashboard) - r.Get("/pear.json", configHandler.Pear) - - r.Route("/upload", func(r chi.Router) { - r.Use(mi.Audit(sm, log)) - r.Get("/img", uploadHandler.Img) - r.Get("/file", uploadHandler.File) - r.Get("/multi_files", uploadHandler.MultiFiles) - }) - - r.Route("/system", func(r chi.Router) { - r.Use(mi.Audit(sm, log)) - - r.Get("/menus", menuHandler.Menus) - - r.Route("/config", func(r chi.Router) { - r.Get("/list", configHandler.List) - r.Post("/list", configHandler.List) - r.Get("/add", configHandler.Add) - r.Get("/edit", configHandler.Edit) - r.Post("/save", configHandler.Save) - r.Post("/refresh_cache", configHandler.RefreshCache) - r.Post("/reset_pear", configHandler.ResetPear) - }) - - r.Route("/menu", func(r chi.Router) { - r.Get("/list", menuHandler.List) - r.Post("/list", menuHandler.List) - r.Get("/add", menuHandler.Add) - r.Get("/add_children", menuHandler.AddChildren) - r.Get("/edit", menuHandler.Edit) - r.Post("/save", menuHandler.Save) - r.Post("/data", menuHandler.Data) - r.Post("/refresh_cache", menuHandler.RefreshCache) - }) - - r.Route("/department", func(r chi.Router) { - r.Get("/list", departmentHandler.List) - r.Post("/list", departmentHandler.List) - r.Get("/add", departmentHandler.Add) - r.Get("/add_children", departmentHandler.AddChildren) - r.Get("/edit", departmentHandler.Edit) - r.Post("/save", departmentHandler.Save) - r.Post("/data", departmentHandler.Data) - r.Post("/refresh_cache", departmentHandler.RefreshCache) - r.Post("/rebuild_parent_path", departmentHandler.RebuildParentPath) - }) - - r.Route("/role", func(r chi.Router) { - r.Get("/list", roleHandler.List) - r.Post("/list", roleHandler.List) - r.Get("/add", roleHandler.Add) - r.Get("/add_children", roleHandler.AddChildren) - r.Get("/edit", roleHandler.Edit) - r.Post("/save", roleHandler.Save) - r.Post("/data", roleHandler.Data) - r.Post("/refresh_cache", roleHandler.RefreshCache) - r.Post("/rebuild_parent_path", roleHandler.RebuildParentPath) - r.Post("/refresh_role_menus", roleHandler.RefreshRoleMenus) - r.Get("/set_menu", roleHandler.SetMenu) - r.Post("/set_menu", roleHandler.SetMenu) - }) - - r.Route("/user", func(r chi.Router) { - r.Get("/list", userHandler.List) - r.Post("/list", userHandler.List) - r.Get("/add", userHandler.Add) - r.Get("/edit", userHandler.Edit) - r.Post("/save", userHandler.Save) - r.Get("/profile", userHandler.Profile) - r.Post("/data", userHandler.Data) - }) - - r.Route("/login_log", func(r chi.Router) { - r.Get("/list", loginLogHandler.List) - r.Post("/list", loginLogHandler.List) - }) - - r.Route("/audit_log", func(r chi.Router) { - r.Get("/list", auditHandler.List) - r.Post("/list", auditHandler.List) - }) - }) - }) - - }) - - return r -} diff --git a/internal/erpserver/repository/store.go b/internal/erpserver/repository/store.go index 221258d..ba61a51 100644 --- a/internal/erpserver/repository/store.go +++ b/internal/erpserver/repository/store.go @@ -52,7 +52,7 @@ func (r *Repository) Transaction(ctx context.Context, fn func(ctx context.Contex }) } -func NewDB(log *logger.Logger, config *config.Config) (*gorm.DB, func(), error) { +func NewDB(config *config.Config, log *logger.Logger) (*gorm.DB, func(), error) { dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%d sslmode=disable TimeZone=Asia/Shanghai", config.DB.Host, config.DB.Username, diff --git a/internal/erpserver/templ/home/home.templ b/internal/erpserver/templ/home/home.templ index 5f05f80..a42fda0 100644 --- a/internal/erpserver/templ/home/home.templ +++ b/internal/erpserver/templ/home/home.templ @@ -117,7 +117,7 @@ templ Home(ctx context.Context) { const popup = layui.popup; // yml | json | api - admin.setConfigurationPath("/pear.json"); + admin.setConfigurationPath("/system/pear.json"); admin.render(); diff --git a/internal/erpserver/templ/home/home_templ.go b/internal/erpserver/templ/home/home_templ.go index f3c1fbc..7fcbdb7 100644 --- a/internal/erpserver/templ/home/home_templ.go +++ b/internal/erpserver/templ/home/home_templ.go @@ -59,7 +59,7 @@ func Home(ctx context.Context) templ.Component { return templ_7745c5c3_Err } } - templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
  • ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "
  • ") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/erpserver/templ/system/user/profile.templ b/internal/erpserver/templ/system/user/profile.templ index ae78d66..35d133e 100644 --- a/internal/erpserver/templ/system/user/profile.templ +++ b/internal/erpserver/templ/system/user/profile.templ @@ -97,11 +97,9 @@ templ profileCss() { templ profileJs(ctx context.Context) { ") + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "") if templ_7745c5c3_Err != nil { return templ_7745c5c3_Err } diff --git a/internal/erpserver/wire.go b/internal/erpserver/wire.go deleted file mode 100644 index 5140f9f..0000000 --- a/internal/erpserver/wire.go +++ /dev/null @@ -1,81 +0,0 @@ -//go:build wireinject -// +build wireinject - -package erpserver - -import ( - "management/internal/erpserver/handler" - commonHandler "management/internal/erpserver/handler/common" - systemHandler "management/internal/erpserver/handler/system" - "management/internal/erpserver/repository" - "management/internal/erpserver/repository/seed" - systemRepo "management/internal/erpserver/repository/system" - "management/internal/erpserver/service/v1" - commonService "management/internal/erpserver/service/v1/common" - systemService "management/internal/erpserver/service/v1/system" - "management/internal/pkg/cache" - "management/internal/pkg/config" - "management/internal/pkg/session" - - "github.com/drhin/logger" - "github.com/google/wire" -) - -var repositorySet = wire.NewSet( - repository.NewDB, - repository.NewRepository, - repository.NewTransaction, - systemRepo.NewUserRepository, - systemRepo.NewLoginLogRepository, - systemRepo.NewAuditLogRepository, - systemRepo.NewRoleRepository, - systemRepo.NewMenuRepository, - systemRepo.NewRoleMenuRepository, - systemRepo.NewDepartmentRepository, - systemRepo.NewConfigRepository, - seed.NewSeed, -) - -var serviceSet = wire.NewSet( - v1.NewService, - commonService.NewCaptchaService, - systemService.NewUserService, - systemService.NewLoginLogService, - systemService.NewAuditLogService, - systemService.NewRoleService, - systemService.NewMenuService, - systemService.NewRoleMenuService, - systemService.NewDepartmentService, - systemService.NewConfigService, -) - -var handlerSet = wire.NewSet( - handler.NewHandler, - commonHandler.NewCaptchaHandler, - commonHandler.NewUploadHandler, - systemHandler.NewHomeHandler, - systemHandler.NewUserHandler, - systemHandler.NewLoginLogHandler, - systemHandler.NewAuditHandler, - systemHandler.NewRoleHandler, - systemHandler.NewMenuHandler, - systemHandler.NewDepartmentHandler, - systemHandler.NewConfigHandler, -) - -var serverSet = wire.NewSet( - NewHTTPServer, - NewApp, -) - -func NewWire(*config.Config, *logger.Logger) (App, func(), error) { - panic(wire.Build( - repositorySet, - cache.ConnectRedis, - cache.NewRedisCache, - session.NewSCSManager, - serviceSet, - handlerSet, - serverSet, - )) -} diff --git a/internal/erpserver/wire_gen.go b/internal/erpserver/wire_gen.go deleted file mode 100644 index 187ba30..0000000 --- a/internal/erpserver/wire_gen.go +++ /dev/null @@ -1,96 +0,0 @@ -// Code generated by Wire. DO NOT EDIT. - -//go:generate go run -mod=mod github.com/google/wire/cmd/wire -//go:build !wireinject -// +build !wireinject - -package erpserver - -import ( - "github.com/drhin/logger" - "github.com/google/wire" - "management/internal/erpserver/handler" - common2 "management/internal/erpserver/handler/common" - system3 "management/internal/erpserver/handler/system" - "management/internal/erpserver/repository" - "management/internal/erpserver/repository/seed" - "management/internal/erpserver/repository/system" - "management/internal/erpserver/service/v1" - "management/internal/erpserver/service/v1/common" - system2 "management/internal/erpserver/service/v1/system" - "management/internal/pkg/cache" - "management/internal/pkg/config" - "management/internal/pkg/session" -) - -// Injectors from wire.go: - -func NewWire(configConfig *config.Config, loggerLogger *logger.Logger) (App, func(), error) { - db, cleanup, err := repository.NewDB(loggerLogger, configConfig) - if err != nil { - return App{}, nil, err - } - repositoryRepository := repository.NewRepository(db, loggerLogger) - configRepository := system.NewConfigRepository(repositoryRepository) - departmentRepository := system.NewDepartmentRepository(repositoryRepository) - roleRepository := system.NewRoleRepository(repositoryRepository) - userRepository := system.NewUserRepository(repositoryRepository) - menuRepository := system.NewMenuRepository(repositoryRepository) - seedSeed := seed.NewSeed(configRepository, departmentRepository, roleRepository, userRepository, menuRepository) - transaction := repository.NewTransaction(repositoryRepository) - client, cleanup2, err := cache.ConnectRedis(configConfig, loggerLogger) - if err != nil { - cleanup() - return App{}, nil, err - } - manager, err := session.NewSCSManager(client, configConfig) - if err != nil { - cleanup2() - cleanup() - return App{}, nil, err - } - cacheCache := cache.NewRedisCache(client) - service := v1.NewService(loggerLogger, transaction, manager, cacheCache) - auditLogRepository := system.NewAuditLogRepository(repositoryRepository) - auditLogService := system2.NewAuditLogService(service, auditLogRepository) - roleService := system2.NewRoleService(service, roleRepository) - roleMenuRepository := system.NewRoleMenuRepository(repositoryRepository) - roleMenuService := system2.NewRoleMenuService(service, roleMenuRepository) - menuService := system2.NewMenuService(service, menuRepository, roleService, roleMenuService) - handlerHandler := handler.NewHandler(configConfig, loggerLogger, manager) - captchaService := common.NewCaptchaService() - captchaHandler := common2.NewCaptchaHandler(handlerHandler, captchaService) - uploadHandler := common2.NewUploadHandler(handlerHandler) - configService := system2.NewConfigService(service, configRepository) - configHandler := system3.NewConfigHandler(handlerHandler, configService) - loginLogRepository := system.NewLoginLogRepository(repositoryRepository) - loginLogService := system2.NewLoginLogService(service, loginLogRepository) - userService := system2.NewUserService(service, userRepository, roleService, loginLogService) - homeHandler := system3.NewHomeHandler(handlerHandler, userService, loginLogService) - departmentService := system2.NewDepartmentService(service, departmentRepository) - userHandler := system3.NewUserHandler(handlerHandler, captchaService, userService, roleService, departmentService) - loginLogHandler := system3.NewLoginLogHandler(handlerHandler, loginLogService) - auditHandler := system3.NewAuditHandler(handlerHandler, auditLogService) - menuHandler := system3.NewMenuHandler(handlerHandler, menuService) - roleHandler := system3.NewRoleHandler(handlerHandler, roleService, menuService) - departmentHandler := system3.NewDepartmentHandler(handlerHandler, departmentService) - mux := NewHTTPServer(manager, loggerLogger, menuService, auditLogService, captchaHandler, uploadHandler, configHandler, homeHandler, userHandler, loginLogHandler, auditHandler, menuHandler, roleHandler, departmentHandler) - app := NewApp(seedSeed, auditLogService, mux) - return app, func() { - cleanup2() - cleanup() - }, nil -} - -// wire.go: - -var repositorySet = wire.NewSet(repository.NewDB, repository.NewRepository, repository.NewTransaction, system.NewUserRepository, system.NewLoginLogRepository, system.NewAuditLogRepository, system.NewRoleRepository, system.NewMenuRepository, system.NewRoleMenuRepository, system.NewDepartmentRepository, system.NewConfigRepository, seed.NewSeed) - -var serviceSet = wire.NewSet(v1.NewService, common.NewCaptchaService, system2.NewUserService, system2.NewLoginLogService, system2.NewAuditLogService, system2.NewRoleService, system2.NewMenuService, system2.NewRoleMenuService, system2.NewDepartmentService, system2.NewConfigService) - -var handlerSet = wire.NewSet(handler.NewHandler, common2.NewCaptchaHandler, common2.NewUploadHandler, system3.NewHomeHandler, system3.NewUserHandler, system3.NewLoginLogHandler, system3.NewAuditHandler, system3.NewRoleHandler, system3.NewMenuHandler, system3.NewDepartmentHandler, system3.NewConfigHandler) - -var serverSet = wire.NewSet( - NewHTTPServer, - NewApp, -) diff --git a/internal/pkg/mid/authorize_v5.go b/internal/pkg/mid/authorize_v5.go index 5af056b..8665beb 100644 --- a/internal/pkg/mid/authorize_v5.go +++ b/internal/pkg/mid/authorize_v5.go @@ -50,7 +50,7 @@ var publicRoutes = map[string]bool{ "/upload/img": true, "/upload/file": true, "/upload/multi_files": true, - "/pear.json": true, + "/system/pear.json": true, "/logout": true, } diff --git a/internal/pkg/render/respond.go b/internal/pkg/render/respond.go new file mode 100644 index 0000000..578bffe --- /dev/null +++ b/internal/pkg/render/respond.go @@ -0,0 +1,95 @@ +package render + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "github.com/a-h/templ" + "github.com/drhin/logger" + "go.uber.org/zap" +) + +type Renderer interface { + Render(ctx context.Context, w http.ResponseWriter, t templ.Component) + + JSON(w http.ResponseWriter, data any) + JSONObj(w http.ResponseWriter, message string, data any) + JSONOk(w http.ResponseWriter, message string) + JSONErr(w http.ResponseWriter, message string) +} + +type render struct { + log *logger.Logger +} + +func NewRender(log *logger.Logger) Renderer { + return &render{ + log: log, + } + +} + +func (r *render) Render(ctx context.Context, w http.ResponseWriter, t templ.Component) { + if err := t.Render(ctx, w); err != nil { + r.log.Error(err.Error(), err, + zap.String("templ render", fmt.Sprintf("%v", t)), + ) + } +} + +func (r *render) JSON(w http.ResponseWriter, data any) { + respond(w, data) +} + +func (r *render) JSONObj(w http.ResponseWriter, message string, data any) { + respond(w, Response{Success: true, Message: message, Data: data}) +} + +func (r *render) JSONOk(w http.ResponseWriter, message string) { + respond(w, Response{Success: true, Message: message}) +} + +func (r *render) JSONErr(w http.ResponseWriter, message string) { + respond(w, Response{Success: false, Message: message}) +} + +type Response struct { + Success bool `json:"success"` + Message string `json:"msg"` + Data any `json:"data"` +} + +type ResponseTree struct { + Status ResponseTreeStatus `json:"status"` + Data any `json:"data"` +} + +type ResponseTreeStatus struct { + Code int `json:"code"` + Message string `json:"message"` +} + +type ResponseList struct { + Code int `json:"code"` + Message string `json:"msg"` + Count int64 `json:"count"` + Data any `json:"data"` +} + +func respond(w http.ResponseWriter, data any) { + v, err := json.Marshal(data) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json; charset=utf-8") + w.WriteHeader(http.StatusOK) + _, err = w.Write(v) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +}