This commit is contained in:
2025-03-31 11:59:42 +08:00
parent 963e1e005e
commit 6fb06c456c
52 changed files with 2244 additions and 753 deletions

View File

@@ -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"`

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.28.0
package db

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.28.0
package db

View File

@@ -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

View File

@@ -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

View File

@@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.27.0
// sqlc v1.28.0
package db

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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,
)

View File

@@ -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

View File

@@ -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
}

View File

@@ -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,
}
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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(),

View File

@@ -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)
}

View File

@@ -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})
}

View File

@@ -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)
}
}

View File

@@ -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,
}
}

View File

@@ -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) {

View File

@@ -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)
}
}

View File

@@ -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, "刷新成功")
}

View File

@@ -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, "刷新成功")
}

View File

@@ -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)
}

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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 {