diff --git a/internal/db/model/dto/search.go b/internal/db/model/dto/search.go index fb1efca..0d2ddf6 100644 --- a/internal/db/model/dto/search.go +++ b/internal/db/model/dto/search.go @@ -4,6 +4,8 @@ type SearchDto struct { SearchTimeBegin string `json:"searchTimeBegin"` SearchTimeEnd string `json:"searchTimeEnd"` SearchStatus int `json:"searchStatus"` + SearchEmail string `json:"searchEmail"` + SearchPhone string `json:"searchPhone"` SearchName string `json:"searchName"` SearchID int64 `json:"searchID"` SearchKey string `json:"searchKey"` diff --git a/internal/db/query/sys_role.sql b/internal/db/query/sys_role.sql index 0885d53..6f01bd6 100644 --- a/internal/db/query/sys_role.sql +++ b/internal/db/query/sys_role.sql @@ -6,10 +6,11 @@ INSERT INTO sys_role ( parent_id, parent_path, status, + sort, created_at, updated_at ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8 + $1, $2, $3, $4, $5, $6, $7, $8, $9 ) RETURNING *; -- name: UpdateSysRole :one diff --git a/internal/db/query/sys_user.sql b/internal/db/query/sys_user.sql index b6717a7..b308a62 100644 --- a/internal/db/query/sys_user.sql +++ b/internal/db/query/sys_user.sql @@ -51,7 +51,9 @@ ORDER BY created_at DESC; -- name: CountSysUserCondition :one SELECT COUNT(*) FROM sys_user WHERE (NOT @is_status::Boolean OR status = @status) - AND (@username::text = '' OR username ILIKE '%' || @username || '%'); + AND (NOT @is_id::Boolean OR id = @id) + AND (@username::text = '' OR username ILIKE '%' || @username || '%') + AND (@email::text = '' OR email ILIKE '%' || @email || '%'); -- name: ListSysUserCondition :many SELECT id, uuid, email, username, avatar, gender, department_id, role_id, status, change_password_at, created_at, updated_at, @@ -61,7 +63,9 @@ SELECT id, uuid, email, username, avatar, gender, department_id, role_id, status WHERE id = sys_user.role_id) AS role_name FROM sys_user WHERE (NOT @is_status::Boolean OR sys_user.status = @status) - AND (@username::text = '' OR username ILIKE '%' || @username || '%') + AND (NOT @is_id::Boolean OR sys_user.id = @id) + AND (@username::text = '' OR sys_user.username ILIKE '%' || @username || '%') + AND (@email::text = '' OR sys_user.email ILIKE '%' || @email || '%') ORDER BY created_at DESC OFFSET @skip LIMIT @size; diff --git a/internal/db/sqlc/budget.sql.go b/internal/db/sqlc/budget.sql.go index baaf187..5613f42 100644 --- a/internal/db/sqlc/budget.sql.go +++ b/internal/db/sqlc/budget.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: budget.sql package db diff --git a/internal/db/sqlc/categroy.sql.go b/internal/db/sqlc/categroy.sql.go index 2fb6c33..78af4b8 100644 --- a/internal/db/sqlc/categroy.sql.go +++ b/internal/db/sqlc/categroy.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: categroy.sql package db diff --git a/internal/db/sqlc/customer.sql.go b/internal/db/sqlc/customer.sql.go index 31bf590..34f0be6 100644 --- a/internal/db/sqlc/customer.sql.go +++ b/internal/db/sqlc/customer.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: customer.sql package db diff --git a/internal/db/sqlc/db.go b/internal/db/sqlc/db.go index b4a3b78..eeee39e 100644 --- a/internal/db/sqlc/db.go +++ b/internal/db/sqlc/db.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 package db diff --git a/internal/db/sqlc/expenses.sql.go b/internal/db/sqlc/expenses.sql.go index 31c9dea..4a65572 100644 --- a/internal/db/sqlc/expenses.sql.go +++ b/internal/db/sqlc/expenses.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: expenses.sql package db diff --git a/internal/db/sqlc/income.sql.go b/internal/db/sqlc/income.sql.go index 2a48c25..31e1f03 100644 --- a/internal/db/sqlc/income.sql.go +++ b/internal/db/sqlc/income.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: income.sql package db diff --git a/internal/db/sqlc/models.go b/internal/db/sqlc/models.go index f5960cb..768f5ce 100644 --- a/internal/db/sqlc/models.go +++ b/internal/db/sqlc/models.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 package db diff --git a/internal/db/sqlc/project.sql.go b/internal/db/sqlc/project.sql.go index aa199fb..b5f64d4 100644 --- a/internal/db/sqlc/project.sql.go +++ b/internal/db/sqlc/project.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: project.sql package db diff --git a/internal/db/sqlc/project_file.sql.go b/internal/db/sqlc/project_file.sql.go index 49b7d04..9954fd8 100644 --- a/internal/db/sqlc/project_file.sql.go +++ b/internal/db/sqlc/project_file.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: project_file.sql package db diff --git a/internal/db/sqlc/querier.go b/internal/db/sqlc/querier.go index 795cbe9..ea061d5 100644 --- a/internal/db/sqlc/querier.go +++ b/internal/db/sqlc/querier.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 package db diff --git a/internal/db/sqlc/sys_audit_log.sql.go b/internal/db/sqlc/sys_audit_log.sql.go index 54f2e3b..f4bcd0c 100644 --- a/internal/db/sqlc/sys_audit_log.sql.go +++ b/internal/db/sqlc/sys_audit_log.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_audit_log.sql package db diff --git a/internal/db/sqlc/sys_config.sql.go b/internal/db/sqlc/sys_config.sql.go index 0700e2b..418a3a2 100644 --- a/internal/db/sqlc/sys_config.sql.go +++ b/internal/db/sqlc/sys_config.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_config.sql package db diff --git a/internal/db/sqlc/sys_department.sql.go b/internal/db/sqlc/sys_department.sql.go index 5701861..53d10d3 100644 --- a/internal/db/sqlc/sys_department.sql.go +++ b/internal/db/sqlc/sys_department.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_department.sql package db diff --git a/internal/db/sqlc/sys_menu.sql.go b/internal/db/sqlc/sys_menu.sql.go index 9f0ed5e..1af092a 100644 --- a/internal/db/sqlc/sys_menu.sql.go +++ b/internal/db/sqlc/sys_menu.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_menu.sql package db diff --git a/internal/db/sqlc/sys_role.sql.go b/internal/db/sqlc/sys_role.sql.go index 6953f18..5198a56 100644 --- a/internal/db/sqlc/sys_role.sql.go +++ b/internal/db/sqlc/sys_role.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_role.sql package db @@ -100,10 +100,11 @@ INSERT INTO sys_role ( parent_id, parent_path, status, + sort, created_at, updated_at ) VALUES ( - $1, $2, $3, $4, $5, $6, $7, $8 + $1, $2, $3, $4, $5, $6, $7, $8, $9 ) RETURNING id, name, display_name, parent_id, parent_path, vip, status, sort, created_at, updated_at ` @@ -114,6 +115,7 @@ type CreateSysRoleParams struct { ParentID int32 `json:"parent_id"` ParentPath string `json:"parent_path"` Status int32 `json:"status"` + Sort int32 `json:"sort"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } @@ -126,6 +128,7 @@ func (q *Queries) CreateSysRole(ctx context.Context, arg *CreateSysRoleParams) ( arg.ParentID, arg.ParentPath, arg.Status, + arg.Sort, arg.CreatedAt, arg.UpdatedAt, ) diff --git a/internal/db/sqlc/sys_role_menu.sql.go b/internal/db/sqlc/sys_role_menu.sql.go index 8c051c8..b46b6ee 100644 --- a/internal/db/sqlc/sys_role_menu.sql.go +++ b/internal/db/sqlc/sys_role_menu.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_role_menu.sql package db diff --git a/internal/db/sqlc/sys_user.sql.go b/internal/db/sqlc/sys_user.sql.go index dc5d23c..df92f51 100644 --- a/internal/db/sqlc/sys_user.sql.go +++ b/internal/db/sqlc/sys_user.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_user.sql package db @@ -27,17 +27,29 @@ func (q *Queries) CountSysUser(ctx context.Context) (int64, error) { const countSysUserCondition = `-- name: CountSysUserCondition :one SELECT COUNT(*) FROM sys_user WHERE (NOT $1::Boolean OR status = $2) - AND ($3::text = '' OR username ILIKE '%' || $3 || '%') + AND (NOT $3::Boolean OR id = $4) + AND ($5::text = '' OR username ILIKE '%' || $5 || '%') + AND ($6::text = '' OR email ILIKE '%' || $6 || '%') ` type CountSysUserConditionParams struct { IsStatus bool `json:"is_status"` Status int32 `json:"status"` + IsID bool `json:"is_id"` + ID int32 `json:"id"` Username string `json:"username"` + Email string `json:"email"` } func (q *Queries) CountSysUserCondition(ctx context.Context, arg *CountSysUserConditionParams) (int64, error) { - row := q.db.QueryRow(ctx, countSysUserCondition, arg.IsStatus, arg.Status, arg.Username) + row := q.db.QueryRow(ctx, countSysUserCondition, + arg.IsStatus, + arg.Status, + arg.IsID, + arg.ID, + arg.Username, + arg.Email, + ) var count int64 err := row.Scan(&count) return count, err @@ -271,16 +283,21 @@ SELECT id, uuid, email, username, avatar, gender, department_id, role_id, status WHERE id = sys_user.role_id) AS role_name FROM sys_user WHERE (NOT $1::Boolean OR sys_user.status = $2) - AND ($3::text = '' OR username ILIKE '%' || $3 || '%') + AND (NOT $3::Boolean OR sys_user.id = $4) + AND ($5::text = '' OR sys_user.username ILIKE '%' || $5 || '%') + AND ($6::text = '' OR sys_user.email ILIKE '%' || $6 || '%') ORDER BY created_at DESC -OFFSET $4 -LIMIT $5 +OFFSET $7 +LIMIT $8 ` type ListSysUserConditionParams struct { IsStatus bool `json:"is_status"` Status int32 `json:"status"` + IsID bool `json:"is_id"` + ID int32 `json:"id"` Username string `json:"username"` + Email string `json:"email"` Skip int32 `json:"skip"` Size int32 `json:"size"` } @@ -306,7 +323,10 @@ func (q *Queries) ListSysUserCondition(ctx context.Context, arg *ListSysUserCond rows, err := q.db.Query(ctx, listSysUserCondition, arg.IsStatus, arg.Status, + arg.IsID, + arg.ID, arg.Username, + arg.Email, arg.Skip, arg.Size, ) diff --git a/internal/db/sqlc/sys_user_login_log.sql.go b/internal/db/sqlc/sys_user_login_log.sql.go index 8b619f4..46237cf 100644 --- a/internal/db/sqlc/sys_user_login_log.sql.go +++ b/internal/db/sqlc/sys_user_login_log.sql.go @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. // versions: -// sqlc v1.27.0 +// sqlc v1.28.0 // source: sys_user_login_log.sql package db diff --git a/internal/erpserver/biz/v1/system/audit.go b/internal/erpserver/biz/v1/system/audit.go index df2b05f..b2f3c69 100644 --- a/internal/erpserver/biz/v1/system/audit.go +++ b/internal/erpserver/biz/v1/system/audit.go @@ -2,18 +2,17 @@ package system import ( "context" + "time" + "management/internal/db/model/dto" db "management/internal/db/sqlc" ) type AuditBiz interface { Create(ctx context.Context, arg *db.CreateSysAuditLogParams) error - - AuditExpansion + List(ctx context.Context, q dto.SearchDto) ([]*db.SysAuditLog, int64, error) } -type AuditExpansion interface{} - type auditBiz struct { store db.Store } @@ -29,3 +28,42 @@ func NewAudit(store db.Store) *auditBiz { func (b *auditBiz) Create(ctx context.Context, arg *db.CreateSysAuditLogParams) error { return b.store.CreateSysAuditLog(ctx, arg) } + +func (b *auditBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.SysAuditLog, int64, error) { + start, err := time.ParseInLocation(time.DateTime, q.SearchTimeBegin, time.Local) + if err != nil { + return nil, 0, err + } + end, err := time.ParseInLocation(time.DateTime, q.SearchTimeEnd, time.Local) + if err != nil { + return nil, 0, err + } + + countArg := &db.CountSysAuditLogConditionParams{ + StartAt: start, + EndAt: end, + Email: q.SearchEmail, + Username: q.SearchName, + } + + dataArg := &db.ListSysAuditLogConditionParams{ + StartAt: start, + EndAt: end, + Email: q.SearchEmail, + Username: q.SearchName, + Skip: (int32(q.Page) - 1) * int32(q.Rows), + Size: int32(q.Rows), + } + + count, err := b.store.CountSysAuditLogCondition(ctx, countArg) + if err != nil { + return nil, 0, err + } + + audits, err := b.store.ListSysAuditLogCondition(ctx, dataArg) + if err != nil { + return nil, 0, err + } + + return audits, count, nil +} diff --git a/internal/erpserver/biz/v1/system/config.go b/internal/erpserver/biz/v1/system/config.go index f1a4a52..00faf21 100644 --- a/internal/erpserver/biz/v1/system/config.go +++ b/internal/erpserver/biz/v1/system/config.go @@ -10,7 +10,6 @@ import ( "management/internal/global/keys" "management/internal/global/pearadmin" "management/internal/pkg/redis" - "management/internal/pkg/session" ) type ConfigBiz interface { @@ -22,18 +21,16 @@ type ConfigExpansion interface { } type configBiz struct { - store db.Store - redis redis.IRedis - session session.ISession + store db.Store + redis redis.IRedis } var _ ConfigBiz = (*configBiz)(nil) -func NewConfig(store db.Store, redis redis.IRedis, session session.ISession) *configBiz { +func NewConfig(store db.Store, redis redis.IRedis) *configBiz { return &configBiz{ - store: store, - redis: redis, - session: session, + store: store, + redis: redis, } } diff --git a/internal/erpserver/biz/v1/system/department.go b/internal/erpserver/biz/v1/system/department.go index a052646..48843cc 100644 --- a/internal/erpserver/biz/v1/system/department.go +++ b/internal/erpserver/biz/v1/system/department.go @@ -11,7 +11,6 @@ import ( "management/internal/erpserver/model/view" "management/internal/global/keys" "management/internal/pkg/redis" - "management/internal/pkg/session" ) type DepartmentBiz interface { @@ -32,18 +31,16 @@ type DepartmentBiz interface { type DepartmentExpansion interface{} type departmentBiz struct { - store db.Store - redis redis.IRedis - session session.ISession + store db.Store + redis redis.IRedis } var _ DepartmentBiz = (*departmentBiz)(nil) -func NewDepartment(store db.Store, redis redis.IRedis, session session.ISession) *departmentBiz { +func NewDepartment(store db.Store, redis redis.IRedis) *departmentBiz { return &departmentBiz{ - store: store, - redis: redis, - session: session, + store: store, + redis: redis, } } @@ -126,52 +123,36 @@ func (b *departmentBiz) Refresh(ctx context.Context) ([]*db.SysDepartment, error return all, nil } -func (h *departmentBiz) RebuildParentPath(ctx context.Context) error { - return h.store.SysDepartmentRebuildPath(ctx) +func (b *departmentBiz) RebuildParentPath(ctx context.Context) error { + return b.store.SysDepartmentRebuildPath(ctx) } -func (h *departmentBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) { - all, err := h.All(ctx) +func (b *departmentBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) { + all, err := b.All(ctx) if err != nil { return nil, err } - return toLayuiTree(id, all), nil + return b.toTree(id, all), nil } -func (h *departmentBiz) XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) { - all, err := h.All(ctx) +func (b *departmentBiz) XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) { + all, err := b.All(ctx) if err != nil { return nil, err } - return toXmSelectTree(id, all), nil + return b.toXmSelectTree(id, all), nil } -func toXmSelectTree(parentId int32, data []*db.SysDepartment) []*view.XmSelectTree { - var res []*view.XmSelectTree - for _, v := range data { - if v.ParentID == parentId { - item := view.XmSelectTree{ - Name: v.Name, - Value: strconv.FormatInt(int64(v.ID), 10), - Children: toXmSelectTree(v.ID, data), - } - res = append(res, &item) - } - } - - return res -} - -func toLayuiTree(parentId int32, data []*db.SysDepartment) []*view.LayuiTree { +func (b *departmentBiz) toTree(parentId int32, data []*db.SysDepartment) []*view.LayuiTree { var res []*view.LayuiTree for _, v := range data { if v.ParentID == parentId { item := view.LayuiTree{} item.ID = strconv.FormatInt(int64(v.ID), 10) item.Title = v.Name - item.Children = toLayuiTree(v.ID, data) + item.Children = b.toTree(v.ID, data) if v.ParentID == 0 { item.Spread = true } @@ -181,3 +162,19 @@ func toLayuiTree(parentId int32, data []*db.SysDepartment) []*view.LayuiTree { return res } + +func (b *departmentBiz) toXmSelectTree(parentId int32, data []*db.SysDepartment) []*view.XmSelectTree { + var res []*view.XmSelectTree + for _, v := range data { + if v.ParentID == parentId { + item := view.XmSelectTree{ + Name: v.Name, + Value: strconv.FormatInt(int64(v.ID), 10), + Children: b.toXmSelectTree(v.ID, data), + } + res = append(res, &item) + } + } + + return res +} diff --git a/internal/erpserver/biz/v1/system/login_log.go b/internal/erpserver/biz/v1/system/login_log.go new file mode 100644 index 0000000..9abe50a --- /dev/null +++ b/internal/erpserver/biz/v1/system/login_log.go @@ -0,0 +1,69 @@ +package system + +import ( + "context" + "time" + + "management/internal/db/model/dto" + db "management/internal/db/sqlc" +) + +type LoginLogBiz interface { + Create(ctx context.Context, arg *db.CreateSysUserLoginLogParams) error + List(ctx context.Context, q dto.SearchDto) ([]*db.SysUserLoginLog, int64, error) +} + +type loginLogBiz struct { + store db.Store +} + +var _ LoginLogBiz = (*loginLogBiz)(nil) + +func NewLoginLog(store db.Store) *loginLogBiz { + return &loginLogBiz{ + store: store, + } +} + +func (b *loginLogBiz) Create(ctx context.Context, arg *db.CreateSysUserLoginLogParams) error { + return b.store.CreateSysUserLoginLog(ctx, arg) +} + +func (b *loginLogBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.SysUserLoginLog, int64, error) { + start, err := time.ParseInLocation(time.DateTime, q.SearchTimeBegin, time.Local) + if err != nil { + return nil, 0, err + } + end, err := time.ParseInLocation(time.DateTime, q.SearchTimeEnd, time.Local) + if err != nil { + return nil, 0, err + } + + countArg := &db.CountSysUserLoginLogConditionParams{ + StartAt: start, + EndAt: end, + Email: q.SearchEmail, + Username: q.SearchName, + } + + dataArg := &db.ListSysUserLoginLogConditionParams{ + StartAt: start, + EndAt: end, + Email: q.SearchEmail, + Username: q.SearchName, + Skip: (int32(q.Page) - 1) * int32(q.Rows), + Size: int32(q.Rows), + } + + count, err := b.store.CountSysUserLoginLogCondition(ctx, countArg) + if err != nil { + return nil, 0, err + } + + logs, err := b.store.ListSysUserLoginLogCondition(ctx, dataArg) + if err != nil { + return nil, 0, err + } + + return logs, count, nil +} diff --git a/internal/erpserver/biz/v1/system/menu.go b/internal/erpserver/biz/v1/system/menu.go index 9050801..6038d17 100644 --- a/internal/erpserver/biz/v1/system/menu.go +++ b/internal/erpserver/biz/v1/system/menu.go @@ -9,9 +9,9 @@ import ( "management/internal/db/model/dto" db "management/internal/db/sqlc" + "management/internal/erpserver/model/view" "management/internal/global/keys" "management/internal/pkg/redis" - "management/internal/pkg/session" ) type MenuBiz interface { @@ -19,34 +19,87 @@ type MenuBiz interface { } type MenuExpansion interface { + Create(ctx context.Context, arg *db.CreateSysMenuParams) (*db.SysMenu, error) + Update(ctx context.Context, arg *db.UpdateSysMenuParams) (*db.SysMenu, error) + Get(ctx context.Context, id int32) (*db.SysMenu, error) GetSysMenuByUrl(ctx context.Context, url string) (*db.SysMenu, error) + AllMenusCache(ctx context.Context) ([]*db.SysMenu, error) + ListMenuTree(ctx context.Context) ([]*db.SysMenuDto, error) ListOwnerMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) + SetOwnerListMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) RecursiveSysMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) SetRecursiveSysMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) MapOwnerMenuByRoleID(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) SetOwnerMapMenuByRoleID(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) + RefreshMenus(ctx context.Context) error + + Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) + XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) } type menuBiz struct { - store db.Store - redis redis.IRedis - session session.ISession + store db.Store + redis redis.IRedis } var _ MenuBiz = (*menuBiz)(nil) -func NewMenu(store db.Store, redis redis.IRedis, session session.ISession) *menuBiz { +func NewMenu(store db.Store, redis redis.IRedis) *menuBiz { return &menuBiz{ - store: store, - redis: redis, - session: session, + store: store, + redis: redis, } } +func (b *menuBiz) Create(ctx context.Context, arg *db.CreateSysMenuParams) (*db.SysMenu, error) { + return b.store.CreateSysMenu(ctx, arg) +} + +func (b *menuBiz) Update(ctx context.Context, arg *db.UpdateSysMenuParams) (*db.SysMenu, error) { + return b.store.UpdateSysMenu(ctx, arg) +} + +func (b *menuBiz) Get(ctx context.Context, id int32) (*db.SysMenu, error) { + return b.store.GetSysMenu(ctx, id) +} + func (b *menuBiz) GetSysMenuByUrl(ctx context.Context, url string) (*db.SysMenu, error) { return b.store.GetSysMenuByUrl(ctx, url) } +func (b *menuBiz) AllMenusCache(ctx context.Context) ([]*db.SysMenu, error) { + key := keys.GetManageKey(ctx, keys.AllMenus) + bs, err := b.redis.GetBytes(ctx, key) + if err == nil { + var res []*db.SysMenu + if err := json.Unmarshal(bs, &res); err == nil { + return res, nil + } + } + + all, err := b.store.AllSysMenu(ctx) + if err != nil { + return nil, err + } + + bs, err = json.Marshal(all) + if err != nil { + return nil, err + } + + _ = redis.Set(ctx, key, bs, time.Hour*6) + return all, nil +} + +func (b *menuBiz) ListMenuTree(ctx context.Context) ([]*db.SysMenuDto, error) { + all, err := b.AllMenusCache(ctx) + if err != nil { + return nil, err + } + + return toTreeSysMenu(0, all), nil +} + func (b *menuBiz) ListOwnerMenuByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) { // 判断redis是否存储 key := keys.GetManageKey(ctx, keys.OwnerMenus, roleID) @@ -187,6 +240,40 @@ func (b *menuBiz) SetOwnerMapMenuByRoleID(ctx context.Context, roleID int32) (ma return result, nil } +func (b *menuBiz) RefreshMenus(ctx context.Context) error { + all, err := b.store.AllSysMenu(ctx) + if err != nil { + return err + } + + bs, err := json.Marshal(all) + if err != nil { + return err + } + + key := keys.GetManageKey(ctx, keys.AllMenus) + err = redis.Set(ctx, key, bs, time.Hour*6) + return err +} + +func (b *menuBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) { + all, err := b.AllMenusCache(ctx) + if err != nil { + return nil, err + } + + return b.toTree(id, all), nil +} + +func (b *menuBiz) XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) { + all, err := b.AllMenusCache(ctx) + if err != nil { + return nil, err + } + + return b.toXmSelectTree(id, all), nil +} + func (b *menuBiz) ownerMenusByRoleID(ctx context.Context, roleID int32) ([]*db.SysMenu, error) { // 判断当前用户是否有vip角色 role, err := b.store.GetSysRole(ctx, roleID) @@ -214,6 +301,68 @@ func (b *menuBiz) ownerMenusByRoleID(ctx context.Context, roleID int32) ([]*db.S return menus, nil } +func (b *menuBiz) toTree(parentId int32, data []*db.SysMenu) []*view.LayuiTree { + var res []*view.LayuiTree + for _, v := range data { + if v.ParentID == parentId { + item := view.LayuiTree{} + item.ID = strconv.FormatInt(int64(v.ID), 10) + item.Title = v.DisplayName + item.Children = b.toTree(v.ID, data) + if v.ParentID == 0 { + item.Spread = true + } + res = append(res, &item) + } + } + + return res +} + +func (b *menuBiz) toXmSelectTree(parentId int32, data []*db.SysMenu) []*view.XmSelectTree { + var res []*view.XmSelectTree + for _, v := range data { + if v.ParentID == parentId { + item := view.XmSelectTree{ + Name: v.DisplayName, + Value: strconv.FormatInt(int64(v.ID), 10), + Children: b.toXmSelectTree(v.ID, data), + } + res = append(res, &item) + } + } + + return res +} + +func toTreeSysMenu(parentId int32, data []*db.SysMenu) []*db.SysMenuDto { + var res []*db.SysMenuDto + for _, v := range data { + if v.ParentID == parentId { + item := db.SysMenuDto{} + item.ID = v.ID + item.Name = v.Name + item.DisplayName = v.DisplayName + item.Url = v.Url + item.Type = v.Type + item.ParentID = v.ParentID + item.ParentPath = v.ParentPath + item.Avatar = v.Avatar + item.Style = v.Style + item.Visible = v.Visible + item.IsList = v.IsList + item.Status = v.Status + item.Sort = v.Sort + item.CreatedAt = v.CreatedAt + item.UpdatedAt = v.UpdatedAt + item.Children = toTreeSysMenu(v.ID, data) + res = append(res, &item) + } + } + + return res +} + func convertToMenuUIDto(data []*db.RecursiveSysMenusRow) []*db.SysMenu { var res []*db.SysMenu diff --git a/internal/erpserver/biz/v1/system/role.go b/internal/erpserver/biz/v1/system/role.go new file mode 100644 index 0000000..f28b34b --- /dev/null +++ b/internal/erpserver/biz/v1/system/role.go @@ -0,0 +1,180 @@ +package system + +import ( + "context" + "encoding/json" + "strconv" + "time" + + "management/internal/db/model/dto" + db "management/internal/db/sqlc" + "management/internal/erpserver/model/view" + "management/internal/global/keys" + "management/internal/pkg/redis" +) + +type RoleBiz interface { + Create(ctx context.Context, arg *db.CreateSysRoleParams) (*db.SysRole, error) + Update(ctx context.Context, arg *db.UpdateSysRoleParams) (*db.SysRole, error) + All(ctx context.Context) ([]*db.SysRole, error) + List(ctx context.Context, q dto.SearchDto) ([]*db.SysRole, int64, error) + Get(ctx context.Context, id int32) (*db.SysRole, error) + Refresh(ctx context.Context) ([]*db.SysRole, error) + RebuildParentPath(ctx context.Context) error + + Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) + XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) + + RoleExpansion +} + +type RoleExpansion interface{} + +type roleBiz struct { + store db.Store + redis redis.IRedis +} + +var _ RoleBiz = (*roleBiz)(nil) + +func NewRole(store db.Store, redis redis.IRedis) *roleBiz { + return &roleBiz{ + store: store, + redis: redis, + } +} + +func (b *roleBiz) Create(ctx context.Context, arg *db.CreateSysRoleParams) (*db.SysRole, error) { + return b.store.CreateSysRole(ctx, arg) +} + +func (b *roleBiz) Update(ctx context.Context, arg *db.UpdateSysRoleParams) (*db.SysRole, error) { + return b.store.UpdateSysRole(ctx, arg) +} + +func (b *roleBiz) All(ctx context.Context) ([]*db.SysRole, error) { + key := keys.GetManageKey(ctx, keys.AllRoles) + bs, err := redis.GetBytes(ctx, key) + if err == nil { + var res []*db.SysRole + if err := json.Unmarshal(bs, &res); err == nil { + return res, nil + } + } + + return b.Refresh(ctx) +} + +func (b *roleBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.SysRole, int64, error) { + countArg := &db.CountSysRoleConditionParams{ + IsStatus: q.SearchStatus != 9999, + Status: int32(q.SearchStatus), + IsID: q.SearchID != 0, + ID: int32(q.SearchID), + IsParentID: q.SearchParentID != 0, + ParentID: int32(q.SearchParentID), + DisplayName: q.SearchName, + } + + dataArg := &db.ListSysRoleConditionParams{ + IsStatus: q.SearchStatus != 9999, + Status: int32(q.SearchStatus), + IsID: q.SearchID != 0, + ID: int32(q.SearchID), + IsParentID: q.SearchParentID != 0, + ParentID: int32(q.SearchParentID), + DisplayName: q.SearchName, + Skip: (int32(q.Page) - 1) * int32(q.Rows), + Size: int32(q.Rows), + } + count, err := b.store.CountSysRoleCondition(ctx, countArg) + if err != nil { + return nil, 0, err + } + + departs, err := b.store.ListSysRoleCondition(ctx, dataArg) + if err != nil { + return nil, 0, err + } + + return departs, count, nil +} + +func (b *roleBiz) Get(ctx context.Context, id int32) (*db.SysRole, error) { + return b.store.GetSysRole(ctx, id) +} + +func (b *roleBiz) Refresh(ctx context.Context) ([]*db.SysRole, error) { + all, err := b.store.AllSysRole(ctx) + if err != nil { + return nil, err + } + + bs, err := json.Marshal(all) + if err != nil { + return nil, err + } + + key := keys.GetManageKey(ctx, keys.AllRoles) + err = redis.Set(ctx, key, bs, time.Hour*6) + if err != nil { + return nil, err + } + return all, nil +} + +func (b *roleBiz) RebuildParentPath(ctx context.Context) error { + return b.store.SysRoleRebuildPath(ctx) +} + +func (b *roleBiz) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) { + all, err := b.All(ctx) + if err != nil { + return nil, err + } + + return b.toTree(id, all), nil +} + +func (b *roleBiz) XmSelect(ctx context.Context, id int32) ([]*view.XmSelectTree, error) { + all, err := b.All(ctx) + if err != nil { + return nil, err + } + + return b.toXmSelectTree(id, all), nil +} + +func (b *roleBiz) toTree(parentId int32, data []*db.SysRole) []*view.LayuiTree { + var res []*view.LayuiTree + for _, v := range data { + if v.ParentID == parentId { + item := view.LayuiTree{} + item.ID = strconv.FormatInt(int64(v.ID), 10) + item.Title = v.DisplayName + item.Children = b.toTree(v.ID, data) + if v.ParentID == 0 { + item.Spread = true + } + res = append(res, &item) + } + } + + return res +} + +func (b *roleBiz) toXmSelectTree(parentId int32, data []*db.SysRole) []*view.XmSelectTree { + var res []*view.XmSelectTree + for _, v := range data { + if v.ParentID == parentId { + item := view.XmSelectTree{ + Name: v.DisplayName, + Value: strconv.FormatInt(int64(v.ID), 10), + Children: b.toXmSelectTree(v.ID, data), + } + res = append(res, &item) + } + } + + return res +} diff --git a/internal/erpserver/biz/v1/system/system.go b/internal/erpserver/biz/v1/system/system.go index e1f089a..2f4a8a6 100644 --- a/internal/erpserver/biz/v1/system/system.go +++ b/internal/erpserver/biz/v1/system/system.go @@ -9,9 +9,11 @@ import ( type SystemBiz interface { UserBiz() UserBiz MenuBiz() MenuBiz + RoleBiz() RoleBiz DepartmentBiz() DepartmentBiz - AuditBiz() AuditBiz ConfigBiz() ConfigBiz + AuditBiz() AuditBiz + LoginLogBiz() LoginLogBiz } type systemBiz struct { @@ -35,17 +37,25 @@ func (b *systemBiz) UserBiz() UserBiz { } func (b *systemBiz) MenuBiz() MenuBiz { - return NewMenu(b.store, b.redis, b.session) + return NewMenu(b.store, b.redis) +} + +func (b *systemBiz) RoleBiz() RoleBiz { + return NewRole(b.store, b.redis) } func (b *systemBiz) DepartmentBiz() DepartmentBiz { - return NewDepartment(b.store, b.redis, b.session) + return NewDepartment(b.store, b.redis) +} + +func (b *systemBiz) ConfigBiz() ConfigBiz { + return NewConfig(b.store, b.redis) } func (b *systemBiz) AuditBiz() AuditBiz { return NewAudit(b.store) } -func (b *systemBiz) ConfigBiz() ConfigBiz { - return NewConfig(b.store, b.redis, b.session) +func (b *systemBiz) LoginLogBiz() LoginLogBiz { + return NewLoginLog(b.store) } diff --git a/internal/erpserver/biz/v1/system/user.go b/internal/erpserver/biz/v1/system/user.go index 6ffac81..618a9dd 100644 --- a/internal/erpserver/biz/v1/system/user.go +++ b/internal/erpserver/biz/v1/system/user.go @@ -17,6 +17,9 @@ import ( // UserBiz 定义处理用户请求所需的方法. type UserBiz interface { Create(ctx context.Context, req *db.CreateSysUserParams) (*db.SysUser, error) + Update(ctx context.Context, req *db.UpdateSysUserParams) (*db.SysUser, error) + List(ctx context.Context, q dto.SearchDto) ([]*db.ListSysUserConditionRow, int64, error) + Get(ctx context.Context, id int32) (*db.SysUser, error) UserExpansion } @@ -46,6 +49,44 @@ func (b *userBiz) Create(ctx context.Context, req *db.CreateSysUserParams) (*db. return b.store.CreateSysUser(ctx, req) } +func (b *userBiz) Update(ctx context.Context, req *db.UpdateSysUserParams) (*db.SysUser, error) { + return b.store.UpdateSysUser(ctx, req) +} + +func (b *userBiz) List(ctx context.Context, q dto.SearchDto) ([]*db.ListSysUserConditionRow, int64, error) { + count, err := b.store.CountSysUserCondition(ctx, &db.CountSysUserConditionParams{ + IsStatus: q.SearchStatus != 9999, + Status: int32(q.SearchStatus), + IsID: q.SearchID != 0, + ID: int32(q.SearchID), + Username: q.SearchName, + Email: q.SearchEmail, + }) + if err != nil { + return nil, 0, err + } + + users, err := b.store.ListSysUserCondition(ctx, &db.ListSysUserConditionParams{ + IsStatus: q.SearchStatus != 9999, + Status: int32(q.SearchStatus), + IsID: q.SearchID != 0, + ID: int32(q.SearchID), + Username: q.SearchName, + Email: q.SearchEmail, + Skip: (int32(q.Page) - 1) * int32(q.Rows), + Size: int32(q.Rows), + }) + if err != nil { + return nil, 0, err + } + + return users, count, nil +} + +func (b *userBiz) Get(ctx context.Context, id int32) (*db.SysUser, error) { + return b.store.GetSysUser(ctx, id) +} + func (b *userBiz) Login(ctx context.Context, req *req.Login) error { log := &db.CreateSysUserLoginLogParams{ CreatedAt: time.Now(), diff --git a/internal/erpserver/handler/common/common.go b/internal/erpserver/handler/common/common.go index 3314bd1..2f047a0 100644 --- a/internal/erpserver/handler/common/common.go +++ b/internal/erpserver/handler/common/common.go @@ -8,6 +8,7 @@ import ( type CommonHandler interface { CaptchaHandler() CaptchaHandler + UploadHandler() UploadHandler } type commonHandler struct { @@ -29,3 +30,7 @@ func NewCommonHandler(conf *config.Config, render tpl.Renderer, biz commonv1.Com func (h *commonHandler) CaptchaHandler() CaptchaHandler { return NewCaptchaHandler(&h.conf.Captcha, h.render, h.biz.CaptchaBiz()) } + +func (h *commonHandler) UploadHandler() UploadHandler { + return NewUploadHandler(h.render) +} diff --git a/internal/erpserver/handler/common/upload.go b/internal/erpserver/handler/common/upload.go new file mode 100644 index 0000000..db550ef --- /dev/null +++ b/internal/erpserver/handler/common/upload.go @@ -0,0 +1,111 @@ +package common + +import ( + "mime/multipart" + "net/http" + + fileutil "management/internal/pkg/file" + "management/internal/pkg/tpl" +) + +type UploadHandler interface { + Img(w http.ResponseWriter, r *http.Request) + File(w http.ResponseWriter, r *http.Request) + MutilFiles(w http.ResponseWriter, r *http.Request) +} + +type uploadHandler struct { + render tpl.Renderer +} + +var _ UploadHandler = (*uploadHandler)(nil) + +func NewUploadHandler(render tpl.Renderer) *uploadHandler { + return &uploadHandler{ + render: render, + } +} + +const maxImageSize = 100 << 20 // 100 MB + +func (h *uploadHandler) Img(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + _, fh, err := r.FormFile("files") + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + path, err := fileutil.UploadFile(fh, fileutil.IMG) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, tpl.Response{Success: true, Message: "ok", Data: path}) +} + +func (h *uploadHandler) File(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + _, fh, err := r.FormFile("files") + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + path, err := fileutil.UploadFile(fh, fileutil.ALL) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, tpl.Response{Success: true, Message: "ok", Data: path}) +} + +type UploadFileRes struct { + Name string `json:"name"` + Path string `json:"path"` +} + +func (h *uploadHandler) MutilFiles(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + + 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.render.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.render.JSON(w, tpl.Response{Success: true, Message: "ok", Data: res}) +} diff --git a/internal/erpserver/handler/system/audit.go b/internal/erpserver/handler/system/audit.go new file mode 100644 index 0000000..095588e --- /dev/null +++ b/internal/erpserver/handler/system/audit.go @@ -0,0 +1,58 @@ +package system + +import ( + "net/http" + + "management/internal/db/model/dto" + "management/internal/erpserver/biz" + "management/internal/pkg/convertor" + "management/internal/pkg/tpl" + "management/internal/router/manage/util" +) + +type AuditHandler interface { + List(w http.ResponseWriter, r *http.Request) +} + +type auditHandler struct { + render tpl.Renderer + biz biz.IBiz +} + +var _ AuditHandler = (*auditHandler)(nil) + +func NewAuditHandler(render tpl.Renderer, biz biz.IBiz) *auditHandler { + return &auditHandler{ + render: render, + biz: biz, + } +} + +func (h *auditHandler) List(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + h.render.HTML(w, r, "audit_log/list.tmpl", nil) + case http.MethodPost: + var q dto.SearchDto + q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) + q.SearchName = r.PostFormValue("name") + 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.biz.SystemV1().AuditBiz().List(r.Context(), q) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + data := tpl.ResponseList{ + Code: 0, + Message: "ok", + Count: count, + Data: res, + } + h.render.JSON(w, data) + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + } +} diff --git a/internal/erpserver/handler/system/config.go b/internal/erpserver/handler/system/config.go index 6c440a4..07b1098 100644 --- a/internal/erpserver/handler/system/config.go +++ b/internal/erpserver/handler/system/config.go @@ -4,7 +4,6 @@ import ( "net/http" "management/internal/erpserver/biz" - "management/internal/pkg/session" "management/internal/pkg/tpl" ) @@ -23,19 +22,17 @@ type ConfigExpansion interface { // configHandler 是 ConfigHandler 接口的实现. type configHandler struct { - render tpl.Renderer - session session.ISession - biz biz.IBiz + render tpl.Renderer + biz biz.IBiz } // 确保 userHandler 实现了 ConfigHandler 接口. var _ ConfigHandler = (*configHandler)(nil) -func NewConfigHandler(render tpl.Renderer, session session.ISession, biz biz.IBiz) *configHandler { +func NewConfigHandler(render tpl.Renderer, biz biz.IBiz) *configHandler { return &configHandler{ - render: render, - session: session, - biz: biz, + render: render, + biz: biz, } } diff --git a/internal/erpserver/handler/system/department.go b/internal/erpserver/handler/system/department.go index 87b1866..f5d4ea1 100644 --- a/internal/erpserver/handler/system/department.go +++ b/internal/erpserver/handler/system/department.go @@ -38,10 +38,10 @@ func NewDepartmentHandler(render tpl.Renderer, biz biz.IBiz) *departmentHandler } func (h *departmentHandler) List(w http.ResponseWriter, r *http.Request) { - if r.Method == http.MethodGet { + switch r.Method { + case http.MethodGet: h.render.HTML(w, r, "department/list.tmpl", nil) - return - } else if r.Method == http.MethodPost { + case http.MethodPost: var q dto.SearchDto q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999) q.SearchParentID = convertor.ConvertInt(r.PostFormValue("parentId"), 0) @@ -62,10 +62,9 @@ func (h *departmentHandler) List(w http.ResponseWriter, r *http.Request) { Data: res, } h.render.JSON(w, data) - return + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } - - http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } func (h *departmentHandler) Add(w http.ResponseWriter, r *http.Request) { diff --git a/internal/erpserver/handler/system/login_log.go b/internal/erpserver/handler/system/login_log.go new file mode 100644 index 0000000..9e5e5fd --- /dev/null +++ b/internal/erpserver/handler/system/login_log.go @@ -0,0 +1,58 @@ +package system + +import ( + "net/http" + + "management/internal/db/model/dto" + "management/internal/erpserver/biz" + "management/internal/pkg/convertor" + "management/internal/pkg/tpl" + "management/internal/router/manage/util" +) + +type LoginLogHandler interface { + List(w http.ResponseWriter, r *http.Request) +} + +type loginLogHandler struct { + render tpl.Renderer + biz biz.IBiz +} + +var _ LoginLogHandler = (*loginLogHandler)(nil) + +func NewLoginLogHandler(render tpl.Renderer, biz biz.IBiz) *loginLogHandler { + return &loginLogHandler{ + render: render, + biz: biz, + } +} + +func (h *loginLogHandler) List(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + h.render.HTML(w, r, "login_log/list.tmpl", nil) + case http.MethodPost: + var q dto.SearchDto + q.SearchTimeBegin, q.SearchTimeEnd = util.DefaultStartTimeAndEndTime(r.PostFormValue("timeBegin"), r.PostFormValue("timeEnd")) + q.SearchName = r.PostFormValue("name") + 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.biz.SystemV1().LoginLogBiz().List(r.Context(), q) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + data := tpl.ResponseList{ + Code: 0, + Message: "ok", + Count: count, + Data: res, + } + h.render.JSON(w, data) + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + } +} diff --git a/internal/erpserver/handler/system/menu.go b/internal/erpserver/handler/system/menu.go index 4cb8ae5..6a0e8f5 100644 --- a/internal/erpserver/handler/system/menu.go +++ b/internal/erpserver/handler/system/menu.go @@ -3,20 +3,37 @@ package system import ( "encoding/json" "net/http" + "strconv" + "strings" + "time" "management/internal/db/model/dto" + db "management/internal/db/sqlc" "management/internal/erpserver/biz" "management/internal/global/know" + "management/internal/pkg/convertor" "management/internal/pkg/session" "management/internal/pkg/tpl" + + "github.com/google/uuid" ) +const style = "layui-btn-primary layui-btn-sm" + type MenuHandler interface { MenuExpansion } type MenuExpansion interface { Menus(w http.ResponseWriter, r *http.Request) + + List(w http.ResponseWriter, r *http.Request) + Add(w http.ResponseWriter, r *http.Request) + AddChildren(w http.ResponseWriter, r *http.Request) + Edit(w http.ResponseWriter, r *http.Request) + Save(w http.ResponseWriter, r *http.Request) + Tree(w http.ResponseWriter, r *http.Request) + Refresh(w http.ResponseWriter, r *http.Request) } type menuHandler struct { @@ -51,3 +68,189 @@ func (h *menuHandler) Menus(w http.ResponseWriter, r *http.Request) { h.render.JSON(w, menus) } + +func (h *menuHandler) List(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + h.render.HTML(w, r, "menu/list.tmpl", nil) + case http.MethodPost: + res, err := h.biz.SystemV1().MenuBiz().ListMenuTree(r.Context()) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + data := tpl.ResponseList{ + Code: 0, + Message: "ok", + Count: 0, + Data: res, + } + h.render.JSON(w, data) + default: + h.render.JSONERR(w, "method not allowed") + } +} + +func (h *menuHandler) Add(w http.ResponseWriter, r *http.Request) { + h.render.HTML(w, r, "menu/edit.tmpl", map[string]any{ + "Item": &db.SysMenu{Style: style, Visible: true, Sort: 6666}, + }) +} + +func (h *menuHandler) AddChildren(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + parentID := convertor.QueryInt[int32](vars, "parentID", 0) + vm := &db.SysMenu{ParentID: int32(parentID), Style: style, Visible: true, Sort: 6666} + parent, err := h.biz.SystemV1().MenuBiz().Get(r.Context(), parentID) + if err == nil { + if parent.Type == "node" { + vm.Type = "menu" + } else if parent.Type == "menu" { + vm.Type = "btn" + } + } + h.render.HTML(w, r, "menu/edit.tmpl", map[string]any{ + "Item": vm, + }) +} + +func (h *menuHandler) Edit(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + id := convertor.QueryInt[int32](vars, "id", 0) + vm := &db.SysMenu{Style: style, Sort: 6666} + if id > 0 { + vm, _ = h.biz.SystemV1().MenuBiz().Get(r.Context(), id) + } + h.render.HTML(w, r, "menu/edit.tmpl", map[string]any{ + "Item": vm, + }) +} + +func (h *menuHandler) Save(w http.ResponseWriter, r *http.Request) { + id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) + name := r.PostFormValue("Name") + dispalyName := r.PostFormValue("DisplayName") + t := r.PostFormValue("Type") + url := r.PostFormValue("Url") + if len(url) == 0 { + url = uuid.Must(uuid.NewRandom()).String() + } + avatar := r.PostFormValue("Avatar") + style := r.PostFormValue("Style") + parentID := convertor.ConvertInt[int32](r.PostFormValue("ParentID"), 0) + visible := convertor.ConvertBool(r.PostFormValue("Visible"), false) + isList := convertor.ConvertBool(r.PostFormValue("IsList"), false) + sort := convertor.ConvertInt[int32](r.PostFormValue("Sort"), 6666) + status := convertor.ConvertInt[int32](r.PostFormValue("Status"), 0) + + ctx := r.Context() + if len(avatar) > 0 && !strings.Contains(avatar, "layui-icon ") { + avatar = "layui-icon " + avatar + } + + parentPath := "" + if parentID > 0 { + parent, err := h.biz.SystemV1().MenuBiz().Get(ctx, parentID) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + parentPath = parent.ParentPath + "," + strconv.Itoa(int(parentID)) + "," + parentPath = strings.ReplaceAll(parentPath, ",,", ",") + } + + if id == 0 { + arg := &db.CreateSysMenuParams{ + Name: name, + DisplayName: dispalyName, + Url: url, + Type: t, + ParentID: int32(parentID), + ParentPath: parentPath, + Avatar: avatar, + Style: style, + Visible: visible, + IsList: isList, + Status: status, + Sort: sort, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + _, err := h.biz.SystemV1().MenuBiz().Create(ctx, arg) + if err != nil { + if db.IsUniqueViolation(err) { + h.render.JSONERR(w, "菜单已存在") + return + } + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "添加成功") + } else { + res, err := h.biz.SystemV1().MenuBiz().Get(ctx, id) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + arg := &db.UpdateSysMenuParams{ + ID: res.ID, + Name: name, + DisplayName: dispalyName, + Url: url, + Type: t, + ParentID: parentID, + ParentPath: parentPath, + Avatar: avatar, + Style: style, + Visible: visible, + IsList: isList, + Status: status, + Sort: sort, + UpdatedAt: time.Now(), + } + _, err = h.biz.SystemV1().MenuBiz().Update(ctx, arg) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "更新成功") + } +} + +func (h *menuHandler) Tree(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := r.URL.Query() + if vars.Get("type") == "xmselect" { + res, err := h.biz.SystemV1().MenuBiz().XmSelect(ctx, 0) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, res) + return + } else { + res, err := h.biz.SystemV1().MenuBiz().Tree(ctx, 0) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, res) + return + } +} + +func (h *menuHandler) Refresh(w http.ResponseWriter, r *http.Request) { + err := h.biz.SystemV1().MenuBiz().RefreshMenus(r.Context()) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "刷新成功") +} diff --git a/internal/erpserver/handler/system/role.go b/internal/erpserver/handler/system/role.go new file mode 100644 index 0000000..b88c96f --- /dev/null +++ b/internal/erpserver/handler/system/role.go @@ -0,0 +1,249 @@ +package system + +import ( + "fmt" + "net/http" + "time" + + "management/internal/db/model/dto" + db "management/internal/db/sqlc" + "management/internal/erpserver/biz" + "management/internal/pkg/convertor" + "management/internal/pkg/tpl" +) + +type RoleHandler interface { + List(w http.ResponseWriter, r *http.Request) + Add(w http.ResponseWriter, r *http.Request) + AddChildren(w http.ResponseWriter, r *http.Request) + Edit(w http.ResponseWriter, r *http.Request) + Save(w http.ResponseWriter, r *http.Request) + Tree(w http.ResponseWriter, r *http.Request) + Refresh(w http.ResponseWriter, r *http.Request) + RebuildParentPath(w http.ResponseWriter, r *http.Request) + RefreshRoleMenus(w http.ResponseWriter, r *http.Request) +} + +type roleHandler struct { + render tpl.Renderer + biz biz.IBiz +} + +var _ RoleHandler = (*roleHandler)(nil) + +func NewRoleHandler(render tpl.Renderer, biz biz.IBiz) *roleHandler { + return &roleHandler{ + render: render, + biz: biz, + } +} + +func (h *roleHandler) List(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + h.render.HTML(w, r, "role/list.tmpl", nil) + case http.MethodPost: + var q dto.SearchDto + q.SearchStatus = convertor.ConvertInt(r.PostFormValue("status"), 9999) + q.SearchParentID = convertor.ConvertInt(r.PostFormValue("parentId"), 0) + q.SearchName = r.PostFormValue("name") + 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.biz.SystemV1().RoleBiz().List(r.Context(), q) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + data := tpl.ResponseList{ + Code: 0, + Message: "ok", + Count: count, + Data: res, + } + h.render.JSON(w, data) + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) + } +} + +func (h *roleHandler) Add(w http.ResponseWriter, r *http.Request) { + h.render.HTML(w, r, "role/edit.tmpl", map[string]any{ + "Item": &db.SysRole{Sort: 6666}, + }) +} + +func (h *roleHandler) AddChildren(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + parentID := convertor.QueryInt(vars, "parentID", 0) + vm := &db.SysRole{ParentID: int32(parentID), Sort: 6666} + h.render.HTML(w, r, "role/edit.tmpl", map[string]any{ + "Item": vm, + }) +} + +func (h *roleHandler) Edit(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + id := convertor.QueryInt[int32](vars, "id", 0) + vm := &db.SysRole{Sort: 6666} + if id > 0 { + vm, _ = h.biz.SystemV1().RoleBiz().Get(r.Context(), id) + } + h.render.HTML(w, r, "role/edit.tmpl", map[string]any{ + "Item": vm, + }) +} + +func (h *roleHandler) Save(w http.ResponseWriter, r *http.Request) { + id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) + name := r.PostFormValue("Name") + parentID := convertor.ConvertInt[int32](r.PostFormValue("ParentID"), 0) + displayName := r.PostFormValue("DisplayName") + sort := convertor.ConvertInt[int32](r.PostFormValue("Sort"), 6666) + status := convertor.ConvertInt[int32](r.PostFormValue("Status"), 0) + + ctx := r.Context() + var parent *db.SysRole + if parentID > 0 { + var err error + parent, err = h.biz.SystemV1().RoleBiz().Get(ctx, parentID) + if err != nil { + h.render.JSONERR(w, "父级节点错误") + return + } + } else { + parent = &db.SysRole{ + ID: 0, + ParentID: 0, + ParentPath: ",0,", + } + } + + if id == 0 { + arg := &db.CreateSysRoleParams{ + Name: name, + DisplayName: displayName, + Vip: false, + ParentID: parent.ID, + ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID), + Status: status, + Sort: sort, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + _, err := h.biz.SystemV1().RoleBiz().Create(ctx, arg) + if err != nil { + if db.IsUniqueViolation(err) { + h.render.JSONERR(w, "角色名称已存在") + return + } + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "添加成功") + } else { + res, err := h.biz.SystemV1().RoleBiz().Get(ctx, id) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + arg := &db.UpdateSysRoleParams{ + ID: res.ID, + DisplayName: displayName, + Status: status, + ParentID: parent.ID, + ParentPath: fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID), + Sort: sort, + UpdatedAt: time.Now(), + } + _, err = h.biz.SystemV1().RoleBiz().Update(ctx, arg) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "更新成功") + } +} + +func (h *roleHandler) Tree(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := r.URL.Query() + if vars.Get("type") == "xmselect" { + res, err := h.biz.SystemV1().RoleBiz().XmSelect(ctx, 0) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, res) + return + } else { + res, err := h.biz.SystemV1().RoleBiz().Tree(ctx, 0) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSON(w, res) + return + } +} + +func (h *roleHandler) Refresh(w http.ResponseWriter, r *http.Request) { + _, err := h.biz.SystemV1().RoleBiz().Refresh(r.Context()) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "刷新成功") +} + +func (h *roleHandler) RebuildParentPath(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + err := h.biz.SystemV1().RoleBiz().RebuildParentPath(ctx) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "重建成功") +} + +func (h *roleHandler) RefreshRoleMenus(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + + // 获取需要刷新的角色ID + roleID := convertor.ConvertInt[int32](r.PostFormValue("roleID"), 0) + sysRole, err := h.biz.SystemV1().RoleBiz().Get(ctx, int32(roleID)) + if err != nil || sysRole == nil { + h.render.JSONERR(w, err.Error()) + return + } + + // 刷新角色菜单 (角色所拥有的菜单集合) + _, err = h.biz.SystemV1().MenuBiz().SetOwnerListMenuByRoleID(ctx, sysRole.ID) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + // 刷新角色菜单 (角色所拥有的菜单集合) + _, err = h.biz.SystemV1().MenuBiz().SetOwnerMapMenuByRoleID(ctx, sysRole.ID) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + // 刷新角色菜单树 (pear admin layui 使用的格式) + _, err = h.biz.SystemV1().MenuBiz().SetRecursiveSysMenus(ctx, sysRole.ID) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "刷新成功") +} diff --git a/internal/erpserver/handler/system/system.go b/internal/erpserver/handler/system/system.go index 9bbe6e4..7716e8e 100644 --- a/internal/erpserver/handler/system/system.go +++ b/internal/erpserver/handler/system/system.go @@ -12,8 +12,11 @@ type SystemHandler interface { Home(w http.ResponseWriter, req *http.Request) UserHandler() UserHandler MenuHandler() MenuHandler + RoleHandler() RoleHandler DepartmentHandler() DepartmentHandler ConfigHandler() ConfigHandler + AuditHandler() AuditHandler + LoginLogHandler() LoginLogHandler } type systemHandler struct { @@ -44,10 +47,22 @@ func (h *systemHandler) MenuHandler() MenuHandler { return NewMenuHandler(h.render, h.session, h.biz) } +func (h *systemHandler) RoleHandler() RoleHandler { + return NewRoleHandler(h.render, h.biz) +} + func (h *systemHandler) DepartmentHandler() DepartmentHandler { return NewDepartmentHandler(h.render, h.biz) } func (h *systemHandler) ConfigHandler() ConfigHandler { - return NewConfigHandler(h.render, h.session, h.biz) + return NewConfigHandler(h.render, h.biz) +} + +func (h *systemHandler) AuditHandler() AuditHandler { + return NewAuditHandler(h.render, h.biz) +} + +func (h *systemHandler) LoginLogHandler() LoginLogHandler { + return NewLoginLogHandler(h.render, h.biz) } diff --git a/internal/erpserver/handler/system/user.go b/internal/erpserver/handler/system/user.go index 5878b10..e698417 100644 --- a/internal/erpserver/handler/system/user.go +++ b/internal/erpserver/handler/system/user.go @@ -4,14 +4,24 @@ import ( "encoding/json" "net/http" "strings" + "time" "management/internal/db/model/dto" + db "management/internal/db/sqlc" "management/internal/erpserver/biz" "management/internal/erpserver/model/req" + "management/internal/global" + "management/internal/global/html" "management/internal/global/know" + "management/internal/middleware/manage/auth" + "management/internal/pkg/convertor" + "management/internal/pkg/crypto" + "management/internal/pkg/rand" "management/internal/pkg/session" "management/internal/pkg/tpl" + "management/internal/router/manage/util" + "github.com/google/uuid" "github.com/zhang2092/browser" ) @@ -20,6 +30,8 @@ type UserHandler interface { Edit(w http.ResponseWriter, r *http.Request) Save(w http.ResponseWriter, r *http.Request) List(w http.ResponseWriter, r *http.Request) + Profile(w http.ResponseWriter, r *http.Request) + Tree(w http.ResponseWriter, r *http.Request) UserExpansion } @@ -47,17 +59,190 @@ func NewUserHandler(render tpl.Renderer, session session.ISession, biz biz.IBiz) } } -func (h *userHandler) Add(w http.ResponseWriter, r *http.Request) {} +func (h *userHandler) Add(w http.ResponseWriter, r *http.Request) { + h.render.HTML(w, r, "user/edit.tmpl", map[string]any{ + "Item": &db.SysUser{ + HashedPassword: nil, + }, + }) +} -func (h *userHandler) Edit(w http.ResponseWriter, r *http.Request) {} +func (h *userHandler) Edit(w http.ResponseWriter, r *http.Request) { + vars := r.URL.Query() + id := convertor.QueryInt[int32](vars, "id", 0) + sysUser := &db.SysUser{} + if id > 0 { + ctx := r.Context() + if user, err := h.biz.SystemV1().UserBiz().Get(ctx, id); err == nil { + user.HashedPassword = nil + sysUser = user + } + } + h.render.HTML(w, r, "user/edit.tmpl", map[string]any{ + "Item": sysUser, + }) +} -func (h *userHandler) Save(w http.ResponseWriter, r *http.Request) {} +func (h *userHandler) Save(w http.ResponseWriter, r *http.Request) { + id := convertor.ConvertInt[int32](r.PostFormValue("ID"), 0) + email := r.PostFormValue("Email") + username := r.PostFormValue("Username") + password := r.PostFormValue("Password") + changePassword := r.PostFormValue("ChangePassword") + gender := convertor.ConvertInt[int32](r.PostFormValue("Gender"), 0) + avatar := r.PostFormValue("File") + status := convertor.ConvertInt[int32](r.PostFormValue("Status"), 0) -func (h *userHandler) List(w http.ResponseWriter, r *http.Request) {} + ctx := r.Context() + departmentID := convertor.ConvertInt[int32](r.PostFormValue("DepartmentID"), 0) + var department *db.SysDepartment + var err error + if departmentID > 0 { + department, err = h.biz.SystemV1().DepartmentBiz().Get(ctx, departmentID) + if err != nil { + h.render.JSONERR(w, "部门数据错误") + return + } + } + var role *db.SysRole + roleID := convertor.ConvertInt[int32](r.PostFormValue("RoleID"), 0) + if roleID > 0 { + role, err = h.biz.SystemV1().RoleBiz().Get(ctx, roleID) + if err != nil { + h.render.JSONERR(w, "角色数据错误") + return + } + } + + if id == 0 { + salt, err := rand.String(10) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + hashedPassword, err := crypto.BcryptHashPassword(password + salt) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + initTime, err := time.ParseInLocation(time.DateTime, "0001-01-01 00:00:00", time.Local) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + arg := &db.CreateSysUserParams{ + Uuid: uuid.Must(uuid.NewV7()), + Email: email, + Username: username, + HashedPassword: hashedPassword, + Salt: salt, + Avatar: avatar, + Gender: gender, + DepartmentID: department.ID, + RoleID: role.ID, + Status: status, + ChangePasswordAt: initTime, + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + } + _, err = h.biz.SystemV1().UserBiz().Create(ctx, arg) + if err != nil { + if db.IsUniqueViolation(err) { + h.render.JSONERR(w, "数据已存在") + return + } + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "添加成功") + } else { + res, err := h.biz.SystemV1().UserBiz().Get(ctx, id) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + arg := &db.UpdateSysUserParams{ + ID: res.ID, + Username: username, + HashedPassword: res.HashedPassword, + Avatar: avatar, + Gender: int32(gender), + DepartmentID: department.ID, + RoleID: role.ID, + Status: int32(status), + ChangePasswordAt: res.ChangePasswordAt, + UpdatedAt: time.Now(), + } + if changePassword == "on" { + hashedPassword, err := crypto.BcryptHashPassword(password + res.Salt) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + arg.HashedPassword = hashedPassword + arg.ChangePasswordAt = time.Now() + } + _, err = h.biz.SystemV1().UserBiz().Update(ctx, arg) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + h.render.JSONOK(w, "更新成功") + } +} + +func (h *userHandler) List(w http.ResponseWriter, r *http.Request) { + switch r.Method { + case http.MethodGet: + h.render.HTML(w, r, "user/list.tmpl", map[string]any{ + "Statuses": html.NewSelectControls(global.SearchStatuses, 0), + }) + case http.MethodPost: + var q dto.SearchDto + q.SearchStatus = util.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 = util.ConvertInt(r.PostFormValue("page"), 1) + q.Rows = util.ConvertInt(r.PostFormValue("rows"), 10) + res, count, err := h.biz.SystemV1().UserBiz().List(r.Context(), q) + if err != nil { + h.render.JSONERR(w, err.Error()) + return + } + + data := tpl.ResponseList{ + Code: 0, + Message: "ok", + Count: count, + Data: res, + } + h.render.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() + user := auth.AuthUser(ctx) + vm, _ := h.biz.SystemV1().UserBiz().Get(ctx, user.ID) + h.render.HTML(w, r, "user/profile.tmpl", map[string]any{ + "Item": vm, + }) +} + +func (h *userHandler) Tree(w http.ResponseWriter, r *http.Request) {} func (h *userHandler) Login(w http.ResponseWriter, r *http.Request) { ctx := r.Context() - if r.Method == http.MethodGet { + switch r.Method { + case http.MethodGet: var user dto.AuthorizeUser u := h.session.GetBytes(ctx, know.StoreName) if err := json.Unmarshal(u, &user); err == nil { @@ -68,11 +253,9 @@ func (h *userHandler) Login(w http.ResponseWriter, r *http.Request) { return } } - h.session.Destroy(ctx) h.render.HTML(w, r, "oauth/login.tmpl", nil) - return - } else if r.Method == http.MethodPost { + case http.MethodPost: req := &req.Login{ Email: strings.TrimSpace(r.PostFormValue("email")), Password: strings.TrimSpace(r.PostFormValue("password")), @@ -115,10 +298,9 @@ func (h *userHandler) Login(w http.ResponseWriter, r *http.Request) { } h.render.JSONOK(w, "login successful") - return + default: + http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } - - http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed) } func (h *userHandler) Logout(w http.ResponseWriter, r *http.Request) { diff --git a/internal/erpserver/http.go b/internal/erpserver/http.go index 95b87bf..e163e4e 100644 --- a/internal/erpserver/http.go +++ b/internal/erpserver/http.go @@ -34,9 +34,9 @@ func NewRouter(handler handler.IHandler, mw mw.IMiddleware) *chi.Mux { r.Post("/login", handler.SystemHandler().UserHandler().Login) r.Get("/logout", handler.SystemHandler().UserHandler().Logout) - // r.With(auth.Authorize, mw.Audit).Post("/upload/img", commonhandler.UploadImg) - // r.With(auth.Authorize, mw.Audit).Post("/upload/file", commonhandler.UploadFile) - // r.With(auth.Authorize, mw.Audit).Post("/upload/mutilfile", commonhandler.UploadMutilFiles) + r.With(mw.Authorize, mw.Audit).Post("/upload/img", handler.CommonHandler().UploadHandler().Img) + r.With(mw.Authorize, mw.Audit).Post("/upload/file", handler.CommonHandler().UploadHandler().File) + r.With(mw.Authorize, mw.Audit).Post("/upload/mutilfile", handler.CommonHandler().UploadHandler().MutilFiles) r.With(mw.Authorize, mw.Audit).Get("/home.html", handler.SystemHandler().Home) r.With(mw.Authorize).Get("/pear.json", handler.SystemHandler().ConfigHandler().Pear) @@ -68,62 +68,54 @@ func NewRouter(handler handler.IHandler, mw mw.IMiddleware) *chi.Mux { r.Post("/rebuild_parent_path", handler.SystemHandler().DepartmentHandler().RebuildParentPath) }) - // r.Route("/user", func(r chi.Router) { - // r.Use(mw.Audit) - // userHandler := systemhandler.NewSysUserHandler() - // r.Get("/list", userHandler.List) - // r.Post("/list", userHandler.PostList) - // r.Get("/add", userHandler.Add) - // r.Get("/edit", userHandler.Edit) - // r.Post("/save", userHandler.Save) - // r.Get("/profile", userHandler.Profile) - // r.Post("/xmselect", userHandler.XmSelect) - // }) + r.Route("/role", func(r chi.Router) { + r.Use(mw.Audit) + r.Get("/list", handler.SystemHandler().RoleHandler().List) + r.Post("/list", handler.SystemHandler().RoleHandler().List) + r.Get("/add", handler.SystemHandler().RoleHandler().Add) + r.Get("/add_children", handler.SystemHandler().RoleHandler().AddChildren) + r.Get("/edit", handler.SystemHandler().RoleHandler().Edit) + r.Post("/save", handler.SystemHandler().RoleHandler().Save) + r.Post("/tree", handler.SystemHandler().RoleHandler().Tree) + r.Post("/refresh", handler.SystemHandler().RoleHandler().Refresh) + r.Post("/rebuild_parent_path", handler.SystemHandler().RoleHandler().RebuildParentPath) + r.Post("/refresh_role_menus", handler.SystemHandler().RoleHandler().RefreshRoleMenus) + // r.Get("/set_menu", roleHandler.SetMenu) + // r.Post("/set_menu", roleHandler.PostSetMenu) + }) - // r.Route("/login_log", func(r chi.Router) { - // // r.Use(mw.Audit) - // userLoginLogHandler := systemhandler.NewSysUserLoginLogHandler() - // r.Get("/list", userLoginLogHandler.List) - // r.Post("/list", userLoginLogHandler.PostList) - // }) + r.Route("/user", func(r chi.Router) { + r.Get("/list", handler.SystemHandler().UserHandler().List) + r.Post("/list", handler.SystemHandler().UserHandler().List) + r.Get("/add", handler.SystemHandler().UserHandler().Add) + r.Get("/edit", handler.SystemHandler().UserHandler().Edit) + r.Post("/save", handler.SystemHandler().UserHandler().Save) + r.Get("/profile", handler.SystemHandler().UserHandler().Profile) + r.Post("/tree", handler.SystemHandler().UserHandler().Tree) + }) - // r.Route("/audit_log", func(r chi.Router) { - // // r.Use(mw.Audit) - // userAuditLogHandler := systemhandler.NewSysAuditLogHandler() - // r.Get("/list", userAuditLogHandler.List) - // r.Post("/list", userAuditLogHandler.PostList) - // }) + r.Route("/login_log", func(r chi.Router) { + r.Get("/list", handler.SystemHandler().LoginLogHandler().List) + r.Post("/list", handler.SystemHandler().LoginLogHandler().List) + }) - // r.Route("/role", func(r chi.Router) { - // r.Use(mw.Audit) - // roleHandler := systemhandler.NewSysRoleHandler() - // r.Get("/list", roleHandler.List) - // r.Post("/list", roleHandler.PostList) - // r.Get("/add", roleHandler.Add) - // r.Get("/edit", roleHandler.Edit) - // r.Post("/save", roleHandler.Save) - // r.Post("/dtree", roleHandler.DTree) - // r.Post("/refresh", roleHandler.Refresh) - // r.Post("/rebuild_parent_path", roleHandler.RebuildParentPath) - // r.Post("/refresh_role_menus", roleHandler.RefreshRoleMenus) - // r.Post("/xm_select", roleHandler.XmSelect) - // r.Get("/set_menu", roleHandler.SetMenu) - // r.Post("/set_menu", roleHandler.PostSetMenu) - // }) + r.Route("/audit_log", func(r chi.Router) { + r.Get("/list", handler.SystemHandler().AuditHandler().List) + r.Post("/list", handler.SystemHandler().AuditHandler().List) + }) r.Get("/menus", handler.SystemHandler().MenuHandler().Menus) - // r.Route("/menu", func(r chi.Router) { - // r.Use(mw.Audit) - // r.Get("/tree", menuHandler.Tree) - // r.Get("/list", menuHandler.List) - // r.Post("/list", menuHandler.PostList) - // r.Get("/add", menuHandler.Add) - // r.Get("/add_children", menuHandler.AddChildren) - // r.Get("/edit", menuHandler.Edit) - // r.Post("/save", menuHandler.Save) - // r.Post("/xm_select_tree", menuHandler.XmSelectTree) - // r.Post("/refresh_cache", menuHandler.Refresh) - // }) + r.Route("/menu", func(r chi.Router) { + r.Use(mw.Audit) + r.Get("/list", handler.SystemHandler().MenuHandler().List) + r.Post("/list", handler.SystemHandler().MenuHandler().List) + r.Get("/add", handler.SystemHandler().MenuHandler().Add) + r.Get("/add_children", handler.SystemHandler().MenuHandler().AddChildren) + r.Get("/edit", handler.SystemHandler().MenuHandler().Edit) + r.Post("/save", handler.SystemHandler().MenuHandler().Save) + r.Post("/tree", handler.SystemHandler().MenuHandler().Tree) + r.Post("/refresh_cache", handler.SystemHandler().MenuHandler().Refresh) + }) // // 类别 // r.Route("/category", func(r chi.Router) { diff --git a/internal/pkg/convertor/http_form.go b/internal/pkg/convertor/http_form.go index ba5658a..ff1de4a 100644 --- a/internal/pkg/convertor/http_form.go +++ b/internal/pkg/convertor/http_form.go @@ -13,6 +13,15 @@ func ConvertInt[T int | int16 | int32 | int64](value string, defaultValue T) T { return T(i) } +func ConvertBool(value string, defaultValue bool) bool { + b, err := strconv.ParseBool(value) + if err != nil { + return defaultValue + } + + return b +} + func QueryInt[T int | int16 | int32 | int64](vars url.Values, key string, defaultValue T) T { v := vars.Get(key) if len(v) == 0 { diff --git a/management b/management index 0e9b593..2135aca 100755 Binary files a/management and b/management differ diff --git a/modd.conf b/modd.conf index f3b3749..d2b1af5 100644 --- a/modd.conf +++ b/modd.conf @@ -1,5 +1,5 @@ # start manage **/*.go **/**/**/*.tmpl **/**/**/**/*.tmpl !web/*.go !**/*_test.go { prep: go build -o ./management . - daemon +sigterm: ./management manage -c config.dev.yaml + daemon +sigterm: ./management erp -c config.dev.yaml } \ No newline at end of file diff --git a/web/templates/manage/project/list.tmpl b/web/templates/manage/project/list.tmpl index d77c2b6..a6d4ef9 100644 --- a/web/templates/manage/project/list.tmpl +++ b/web/templates/manage/project/list.tmpl @@ -5,8 +5,9 @@ {{ genBtn .AuthorizeMenus "add"}} + + -