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 {
@@ -24,16 +23,14 @@ type ConfigExpansion interface {
type configBiz struct {
store db.Store
redis redis.IRedis
session session.ISession
}
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,
}
}

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 {
@@ -34,16 +33,14 @@ type DepartmentExpansion interface{}
type departmentBiz struct {
store db.Store
redis redis.IRedis
session session.ISession
}
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,
}
}
@@ -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
}
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,
}
}
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"
)
@@ -24,17 +23,15 @@ type ConfigExpansion interface {
// configHandler 是 ConfigHandler 接口的实现.
type configHandler struct {
render tpl.Renderer
session session.ISession
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,
}
}

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,11 +62,10 @@ 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)
}
}
func (h *departmentHandler) Add(w http.ResponseWriter, r *http.Request) {
h.render.HTML(w, r, "department/edit.tmpl", map[string]any{

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,11 +298,10 @@ 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)
}
}
func (h *userHandler) Logout(w http.ResponseWriter, r *http.Request) {
h.session.Destroy(r.Context())

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("/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("/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("/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.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("/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("/login_log", func(r chi.Router) {
r.Get("/list", handler.SystemHandler().LoginLogHandler().List)
r.Post("/list", handler.SystemHandler().LoginLogHandler().List)
})
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 {

Binary file not shown.

View File

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

View File

@@ -7,6 +7,7 @@
<i class="layui-icon layui-icon-search"></i>
</button>
</script>
<!-- 操作栏 -->
<script type="text/html" id="actionBox">
{{ genLink .AuthorizeMenus "edit"}}
@@ -107,7 +108,6 @@
method: "POST",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
where: getQueryParams(),
// height: 'full-100',
height: function () {
return $(window).height() - 22;
},
@@ -115,7 +115,7 @@
limit: 15,
limits: [15, 30, 45, 60, 75, 90],
cols: [[
{ field: 'name', title: '项目名称', align: 'left', fixed: 'left', width: 200 },
{ field: 'name', title: '项目名称', align: 'left', width: 200, fixed: 'left' },
{
field: 'status_name', title: '项目状态', align: 'left', fixed: 'left', width: 90, templet: function (d) {
return '<span style="display:inline-block;color:green">' + d.status_name + '</span>';

View File

@@ -1,77 +1,62 @@
{{template "header"}}
<div class="layui-row layui-col-space15">
<div class="layui-collapse">
<div class="layui-colla-item">
<div class="layui-colla-title">查询</div>
<div class="layui-colla-content layui-show">
<div class="layui-card">
<div class="layui-card-body layui-bzw-table">
<form class="layui-form" action="">
{{.CsrfTokenField}}
<div class="layui-form-item">
<div class="layui-form-item layui-inline">
<input type="text" class="layui-input" id="searchTimeBegin" placeholder="yyyy-MM-dd"
readonly value="{{ monthBegin }}" />
</div>
<div class="layui-form-item layui-inline">
<input type="text" class="layui-input " id="searchTimeEnd" placeholder="yyyy-MM-dd"
readonly value="{{ monthEnd }}" />
</div>
<div class="layui-form-item layui-inline">
<select id="searchName">
<option value="email">邮箱</option>
<option value="username">名称</option>
</select>
</div>
<div class="layui-form-item layui-inline">
<input type="text" id="searchKey" placeholder=""
class="layui-input layui-form-group-input">
</div>
<div class="layui-form-item layui-inline">
<button type="button" class="pear-btn pear-btn-md pear-btn-primary" lay-submit
lay-filter="user-query">
<script id="toolbar" type="text/html">
<button type="button" lay-event="search" lay-on="search" class="layui-btn layui-btn-primary layui-btn-sm">
<i class="layui-icon layui-icon-search"></i>
查询
</button>
<button type="reset" class="pear-btn pear-btn-md" lay-submit
lay-filter="user-reset">
<i class="layui-icon layui-icon-refresh"></i>
重置
</button>
</script>
<div class="search-layer" id="search-layer" style="display: none;">
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">开始时间</label>
<input type="text" name="timeBegin" id="timeBegin" placeholder="yyyy-MM-dd" readonly
value="{{ yearBegin }}" class="layui-input" />
</div>
</div>
</form>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">结束时间</label>
<input type="text" name="timeEnd" id="timeEnd" placeholder="yyyy-MM-dd" readonly value="{{ monthEnd }}"
class="layui-input" />
</div>
</div>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">邮箱</label>
<input type="text" name="email" id="email" placeholder="请输入邮箱" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">用户名</label>
<input type="text" name="username" id="username" placeholder="请输入用户名" autocomplete="off"
class="layui-input">
</div>
</div>
</div>
</div>
<div class="layui-card" style="margin-top: 15px;">
<div class="layui-card-body">
<div class="layui-panel">
<table id="tablelist" lay-filter="tablelist"></table>
</div>
</div>
{{define "js"}}
<script>
layui.use(['table', 'form', 'jquery', 'laydate', 'util'], function () {
layui.use(['jquery', 'table', 'form', 'laydate', 'util'], function () {
let $ = layui.jquery;
let table = layui.table;
let form = layui.form;
let $ = layui.jquery;
let laydate = layui.laydate;
let util = layui.util;
/**开始时间 */
laydate.render({
elem: '#searchTimeBegin',
elem: '#timeBegin',
type: 'datetime',
value: '{{ monthBegin }}',
ready: function (date) {
@@ -83,7 +68,7 @@
/**截止时间 */
laydate.render({
elem: '#searchTimeEnd',
elem: '#timeEnd',
type: 'datetime',
value: '{{ monthEnd }}',
ready: function (date) {
@@ -100,12 +85,16 @@
method: "POST",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
where: getQueryParams(),
height: 'full',
height: function () {
return $(window).height() - 22;
},
page: true,
limit: 15,
limits: [15, 30, 45, 60, 75, 90],
cols: [[
{ field: 'created_at', title: '创建时间', align: 'left', width: 160, templet: function (d) { return !d.created_at ? '' : util.toDateString(d.created_at) } },
{ field: 'email', title: '邮箱', align: 'left', width: 180 },
{ field: 'email', title: '邮箱', align: 'left', width: 180, fixed: 'left' },
{ field: 'username', title: '用户名', align: 'left', width: 100 },
{ field: 'created_at', title: '创建时间', align: 'left', width: 160, templet: function (d) { return !d.created_at ? '' : util.toDateString(d.created_at) } },
{ field: 'method', title: '请求方法', align: 'left', width: 90 },
{ field: 'parameters', title: '请求参数', align: 'left', width: 120 },
{ field: 'url', title: 'URL', align: 'left', width: 300 },
@@ -118,7 +107,7 @@
{ field: 'referer_url', title: 'Referer', align: 'left', width: 300 },
{ field: 'remark', title: '备注', align: 'left', width: 200 },
]],
skin: 'line',
skin: 'grid',
toolbar: '#toolbar',
defaultToolbar: [{
title: '刷新',
@@ -131,26 +120,64 @@
}
});
table.on('toolbar(tablelist)', function (obj) {
switch (obj.event) {
case 'search': search(); break;
case 'refresh': refresh(); break;
}
});
function search() {
layer.open({
type: 1,
offset: '20px',
title: '搜索',
content: $('#search-layer'), // 捕获的元素
shade: 0.1,
shadeClose: false,
scrollbar: false,
resize: false,
move: false,
skin: 'search-layer-open',
area: ['50%', '350px'],
btn: ['搜索', '重置'],
btn1: function (index, layero) {
search_btn();
layer.close(index);
},
btn2: function (index, layero) {
$('#timeBegin').val(formatDate(getCurrentYearStart(), 'YYYY-MM-DD HH:mm:ss'));
$('#timeEnd').val(formatDate(getCurrentMonthEnd(), 'YYYY-MM-DD HH:mm:ss'));
$('#email').val('');
$('#username').val('');
return false;
}
});
}
function refresh() {
table.reload('tablelist');
}
// 搜索条件
function getQueryParams() {
return {
SearchTimeBegin: $('#searchTimeBegin').val(),
SearchTimeEnd: $('#searchTimeEnd').val(),
SearchName: $('#searchName').val(),
SearchKey: $('#searchKey').val()
timeBegin: $('#timeBegin').val(),
timeEnd: $('#timeEnd').val(),
name: $('#username').val(),
email: $('#email').val()
};
}
// 搜索
form.on('submit(user-query)', function (data) {
function search_btn() {
table.reload('tablelist', {
where: getQueryParams(),
page: {
curr: 1
}
})
return false;
});
}
});
</script>
{{end}}

View File

@@ -1,76 +1,62 @@
{{template "header"}}
<div class="layui-row layui-col-space15">
<div class="layui-collapse">
<div class="layui-colla-item">
<div class="layui-colla-title">查询</div>
<div class="layui-colla-content layui-show">
<div class="layui-card">
<div class="layui-card-body layui-bzw-table">
<form class="layui-form" action="">
{{.CsrfTokenField}}
<div class="layui-form-item">
<div class="layui-form-item layui-inline">
<input type="text" class="layui-input" id="searchTimeBegin" placeholder="yyyy-MM-dd"
readonly value="{{ monthBegin }}" />
</div>
<div class="layui-form-item layui-inline">
<input type="text" class="layui-input " id="searchTimeEnd" placeholder="yyyy-MM-dd"
readonly value="{{ monthEnd }}" />
</div>
<div class="layui-form-item layui-inline">
<select id="searchName">
<option value="email">邮箱</option>
<option value="username">名称</option>
</select>
</div>
<div class="layui-form-item layui-inline">
<input type="text" id="searchKey" placeholder=""
class="layui-input layui-form-group-input">
</div>
<div class="layui-form-item layui-inline">
<button type="button" class="pear-btn pear-btn-md pear-btn-primary" lay-submit
lay-filter="user-query">
<script id="toolbar" type="text/html">
<button type="button" lay-event="search" lay-on="search" class="layui-btn layui-btn-primary layui-btn-sm">
<i class="layui-icon layui-icon-search"></i>
查询
</button>
<button type="reset" class="pear-btn pear-btn-md" lay-submit
lay-filter="user-reset">
<i class="layui-icon layui-icon-refresh"></i>
重置
</button>
</script>
<div class="search-layer" id="search-layer" style="display: none;">
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">开始时间</label>
<input type="text" name="timeBegin" id="timeBegin" placeholder="yyyy-MM-dd" readonly
value="{{ yearBegin }}" class="layui-input" />
</div>
</div>
</form>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">结束时间</label>
<input type="text" name="timeEnd" id="timeEnd" placeholder="yyyy-MM-dd" readonly value="{{ monthEnd }}"
class="layui-input" />
</div>
</div>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">邮箱</label>
<input type="text" name="email" id="email" placeholder="请输入邮箱" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">用户名</label>
<input type="text" name="username" id="username" placeholder="请输入用户名" autocomplete="off"
class="layui-input">
</div>
</div>
</div>
</div>
<div class="layui-card" style="margin-top: 15px;">
<div class="layui-card-body">
<div class="layui-panel">
<table id="tablelist" lay-filter="tablelist"></table>
</div>
</div>
{{define "js"}}
<script>
layui.use(['table', 'form', 'jquery', 'laydate', 'util'], function () {
layui.use(['jquery', 'table', 'form', 'laydate', 'util'], function () {
let $ = layui.jquery;
let table = layui.table;
let form = layui.form;
let $ = layui.jquery;
let laydate = layui.laydate;
let util = layui.util;
/**开始时间 */
laydate.render({
elem: '#searchTimeBegin',
elem: '#timeBegin',
type: 'datetime',
value: '{{ monthBegin }}',
ready: function (date) {
@@ -82,7 +68,7 @@
/**截止时间 */
laydate.render({
elem: '#searchTimeEnd',
elem: '#timeEnd',
type: 'datetime',
value: '{{ monthEnd }}',
ready: function (date) {
@@ -99,12 +85,16 @@
method: "POST",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
where: getQueryParams(),
height: 'full',
height: function () {
return $(window).height() - 22;
},
page: true,
limit: 15,
limits: [15, 30, 45, 60, 75, 90],
cols: [[
{ field: 'created_at', title: '创建时间', align: 'left', width: 160, templet: function (d) { return !d.created_at ? '' : util.toDateString(d.created_at) } },
{ field: 'email', title: '邮箱', align: 'left', width: 180 },
{ field: 'email', title: '邮箱', align: 'left', width: 180, fixed: 'left' },
{ field: 'username', title: '用户名', align: 'left', width: 100 },
{ field: 'created_at', title: '创建时间', align: 'left', width: 160, templet: function (d) { return !d.created_at ? '' : util.toDateString(d.created_at) } },
{
field: 'is_success', title: '成功?', align: 'center', width: 80, templet: function (d) {
if (d.is_success) {
@@ -120,7 +110,7 @@
{ field: 'url', title: 'URL', align: 'left', width: 200 },
{ field: 'referer_url', title: 'Referer', align: 'left', width: 300 },
]],
skin: 'line',
skin: 'grid',
toolbar: '#toolbar',
defaultToolbar: [{
title: '刷新',
@@ -133,26 +123,64 @@
}
});
table.on('toolbar(tablelist)', function (obj) {
switch (obj.event) {
case 'search': search(); break;
case 'refresh': refresh(); break;
}
});
function search() {
layer.open({
type: 1,
offset: '20px',
title: '搜索',
content: $('#search-layer'), // 捕获的元素
shade: 0.1,
shadeClose: false,
scrollbar: false,
resize: false,
move: false,
skin: 'search-layer-open',
area: ['50%', '350px'],
btn: ['搜索', '重置'],
btn1: function (index, layero) {
search_btn();
layer.close(index);
},
btn2: function (index, layero) {
$('#timeBegin').val(formatDate(getCurrentYearStart(), 'YYYY-MM-DD HH:mm:ss'));
$('#timeEnd').val(formatDate(getCurrentMonthEnd(), 'YYYY-MM-DD HH:mm:ss'));
$('#email').val('');
$('#username').val('');
return false;
}
});
}
function refresh() {
table.reload('tablelist');
}
// 搜索条件
function getQueryParams() {
return {
SearchTimeBegin: $('#searchTimeBegin').val(),
SearchTimeEnd: $('#searchTimeEnd').val(),
SearchName: $('#searchName').val(),
SearchKey: $('#searchKey').val()
timeBegin: $('#timeBegin').val(),
timeEnd: $('#timeEnd').val(),
name: $('#username').val(),
email: $('#email').val()
};
}
// 搜索
form.on('submit(user-query)', function (data) {
function search_btn() {
table.reload('tablelist', {
where: getQueryParams(),
page: {
curr: 1
}
})
return false;
});
}
});
</script>
{{end}}

View File

@@ -74,9 +74,8 @@
</div>
<div class="layui-form-item">
<label class="layui-form-label">上级菜单</label>
<div class="layui-input-inline">
<div id="classTree"></div>
<input type="hidden" id="ParentID" name="ParentID" value="{{.Item.ParentID}}" />
<div class="layui-input-inline" style="width:300px;">
<ul id="menuTree" class="dtree organizationTree"></ul>
</div>
</div>
<div class="layui-form-item">
@@ -156,7 +155,7 @@
<div class="layui-form-item layui-fixbar btn-fixbar-box">
<div class="layui-input-block">
{{ submitBtn .AuthorizeMenus "save"}}
<button type="button" class="pear-btn pear-btn-sm" lay-on="close">
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" lay-on="close">
<i class="layui-icon layui-icon-close"></i>关闭
</button>
</div>
@@ -183,7 +182,7 @@
let iconPicker = layui.iconPicker;
let util = layui.util;
createClassTree();
getMenuTree();
// 图标选择器
iconPicker.render({
@@ -192,54 +191,6 @@
type: 'fontClass'
});
// 创建菜单分类树
function createClassTree() {
$.ajax({
url: '/system/menu/tree',
type: 'get',
success: function (result) {
success(result);
}
});
function success(data) {
var $ParentId = $('#ParentID');
xmSelect.render({
el: '#classTree',
radio: true,
height: 'auto',
initValue: [$ParentId.val()], // 初始化选中值
prop: {
name: 'title',
value: 'id'
},
data: data,
tree: {
// 是否显示树状结构
show: true,
// 是否严格遵守父子模式
strict: false,
// 是否开启极简模式
simple: false
},
model: {
label: {
block: {
showIcon: false // 隐藏删除按钮
}
}
},
// 选中事件
on: function (data) {
if (data.isAdd) {
$ParentId.val(data.arr[0].id);
}
}
});
}
}
// 表单提交
form.on('submit(save)', function (data) {
$.ajax({
@@ -270,6 +221,44 @@
window.parent.layer.close(parent.layer.getFrameIndex(window.name));
}
});
function getMenuTree() {
$.ajax({
url: "/system/menu/tree?type=xmselect",
type: 'post',
dataType: 'json',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
success: function (res) {
xmSelect.render({
el: '#menuTree',
// 工具栏
toolbar: {
show: true
},
radio: true,
clickClose: true,
tips: '请选择父级',
filterable: true,
data: res,
name: 'ParentID',
initValue: ['{{.Item.ParentID}}'],
tree: {
show: true,
//非严格模式
strict: false,
//默认展开节点的数组, 为 true 时, 展开所有节点
expandedKeys: [1],
},
on: function (data) { },
});
},
error: function (err) {
// 处理请求错误
console.log('请求出错:', err);
}
});
}
});
</script>
{{end}}

View File

@@ -8,11 +8,9 @@
{{ genLink .AuthorizeMenus "add_children" "edit" }}
</script>
<div class="layui-card">
<div class="layui-card-body">
<div class="layui-panel">
<table class="layui-hide" id="tablelist" lay-filter="tablelist"></table>
</div>
</div>
{{define "js"}}
<script>
@@ -23,20 +21,15 @@
let form = layui.form;
let util = layui.util;
loadList();
toolbar();
tableActionTool();
search();
// 加载列表
function loadList() {
treetable.render({
elem: '#tablelist',
url: '/system/menu/list',
method: 'post',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
where: getQueryParams(),
height: 'full',
height: function () {
return $(window).height() - 22;
},
cols: [[
{ field: 'name', title: '名称', width: 360 },
{ field: 'display_name', title: '显示名称', width: 120, align: 'center' },
@@ -89,10 +82,7 @@
}, 'filter', 'exports'],
view: {}
});
}
// 工具栏
function toolbar() {
table.on('toolbar(tablelist)', function (obj) {
switch (obj.event) {
case 'add': add(); break;
@@ -107,7 +97,7 @@
type: 2,
title: '新增菜单',
shade: 0.1,
area: ['95%', '95%'],
area: ['99%', '98%'],
content: "/system/menu/add"
});
}
@@ -132,10 +122,7 @@
function refresh() {
table.reload('tablelist');
}
}
// 表格项操作按钮
function tableActionTool() {
table.on('tool(tablelist)', function (obj) {
switch (obj.event) {
case 'add_children': addChildren(obj); break;
@@ -148,7 +135,7 @@
type: 2,
title: '为 ' + obj.data.display_name + ' 新增子级',
shade: 0.1,
area: ['95%', '95%'],
area: ['99%', '98%'],
content: "/system/menu/add_children?parentID=" + obj.data['id']
});
}
@@ -158,11 +145,10 @@
type: 2,
title: '修改',
shade: 0.1,
area: ['95%', '95%'],
area: ['99%', '98%'],
content: "/system/menu/edit?id=" + obj.data['id']
});
}
}
// 搜索条件
function getQueryParams() {
@@ -174,7 +160,6 @@
// 搜索
function search() {
form.on('submit(menu-query)', function (data) {
table.reloadData('tablelist', {
where: getQueryParams(),
page: {
@@ -182,7 +167,6 @@
}
});
return false;
});
}
});
</script>

View File

@@ -99,7 +99,7 @@
<div class="layui-form-item layui-fixbar btn-fixbar-box">
<div class="layui-input-block">
{{ submitBtn .AuthorizeMenus "save"}}
<button type="button" class="pear-btn pear-btn-sm" lay-on="close">
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" lay-on="close">
<i class="layui-icon layui-icon-close"></i>关闭
</button>
</div>
@@ -119,30 +119,13 @@
{{define "js"}}
<script>
layui.use(['form', 'jquery', 'iconPicker', 'dtree', 'util'], function () {
let form = layui.form;
layui.use(['jquery', 'form', 'xmSelect', 'util'], function () {
let $ = layui.jquery;
let iconPicker = layui.iconPicker;
let dtree = layui.dtree;
let form = layui.form;
let xmSelect = layui.xmSelect;
let util = layui.util;
var dTree = dtree.render({
elem: "#roleTree",
initLevel: "2", // 默认展开层级为1
line: true, // 有线树
ficon: ["1", "-1"], // 设定一级图标样式。0表示方形加减图标8表示小圆点图标
icon: ["0", "2"], // 设定二级图标样式。0表示文件夹图标5表示叶子图标
method: 'POST',
url: "/system/role/dtree",
select: true,
selectInitVal: $('#ParentID').val(),
headers: { 'X-CSRF-Token': $('#csrf_token').val() }
});
// 绑定节点事件
dtree.on("node(roleTree)", function (obj) {
$('#ParentID').val(obj.param.nodeId);
});
getRoleTree();
// 表单提交
form.on('submit(save)', function (data) {
@@ -174,6 +157,43 @@
window.parent.layer.close(parent.layer.getFrameIndex(window.name));
}
});
function getRoleTree() {
$.ajax({
url: "/system/role/tree?type=xmselect",
type: 'post',
dataType: 'json',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
success: function (res) {
xmSelect.render({
el: '#roleTree',
// 工具栏
toolbar: {
show: true
},
radio: true,
clickClose: true,
tips: '请选择父级',
filterable: true,
data: res,
name: 'ParentID',
initValue: ['{{.Item.ParentID}}'],
tree: {
show: true,
//非严格模式
strict: false,
//默认展开节点的数组, 为 true 时, 展开所有节点
expandedKeys: [1],
},
on: function (data) { },
});
},
error: function (err) {
// 处理请求错误
console.log('请求出错:', err);
}
});
}
});
</script>
{{end}}

View File

@@ -291,14 +291,14 @@
function getRoleTree() {
$.ajax({
url: "/system/role/dtree",
url: "/system/role/tree",
type: 'post',
dataType: 'json',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
success: function (res) {
tree.render({
elem: '#roleTree',
data: res.data,
data: res,
onlyIconControl: true, // 是否仅允许节点左侧图标控制展开收缩
showLine: true,
click: function (obj) {

View File

@@ -39,13 +39,13 @@
<div class="layui-form-item">
<div class="layui-form-label">部门</div>
<div class="layui-input-inline" style="width:300px;">
<ul id="depart" class="dtree organizationTree"></ul>
<ul id="departTree" class="dtree organizationTree"></ul>
</div>
</div>
<div class="layui-form-item">
<div class="layui-form-label">角色</div>
<div class="layui-input-inline" style="width:300px;">
<ul id="role" class="dtree organizationTree"></ul>
<ul id="roleTree" class="dtree organizationTree"></ul>
</div>
</div>
<div class="layui-form-item">
@@ -58,8 +58,13 @@
<div class="layui-form-item">
<label class="layui-form-label">密码</label>
<div class="layui-input-inline">
<input type="text" id="Password" name="Password" value="{{.Item.HashedPassword}}"
lay-verify="required" autocomplete="off" placeholder="请输入密码" class="layui-input" />
{{if eq .Item.ID 0}}
<input type="text" id="Password" name="Password" lay-verify="required"
autocomplete="off" placeholder="请输入密码" class="layui-input" />
{{else}}
<input type="text" id="Password" name="Password" autocomplete="off" placeholder="请输入密码"
class="layui-input" />
{{end}}
</div>
</div>
<div class="layui-form-item">
@@ -140,7 +145,7 @@
<div class="layui-form-item layui-fixbar btn-fixbar-box">
<div class="layui-input-block">
{{ submitBtn .AuthorizeMenus "save"}}
<button type="button" class="pear-btn pear-btn-sm" lay-on="close">
<button type="button" class="layui-btn layui-btn-primary layui-btn-sm" lay-on="close">
<i class="layui-icon layui-icon-close"></i>关闭
</button>
</div>
@@ -161,46 +166,14 @@
{{define "js"}}
<script>
layui.use(['form', 'jquery', 'iconPicker', 'dtree', "util"], function () {
let form = layui.form;
layui.use(['jquery', 'form', 'xmSelect', "util"], function () {
let $ = layui.jquery;
let iconPicker = layui.iconPicker;
let dtree = layui.dtree;
let form = layui.form;
let xmSelect = layui.xmSelect;
let util = layui.util;
dtree.render({
elem: "#depart",
initLevel: "2", // 默认展开层级为1
line: true, // 有线树
ficon: ["1", "-1"], // 设定一级图标样式。0表示方形加减图标8表示小圆点图标
icon: ["0", "2"], // 设定二级图标样式。0表示文件夹图标5表示叶子图标
method: 'POST',
url: "/system/department/dtree",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
select: true,
selectInitVal: $('#DepartmentID').val()
});
// 单击节点 监听事件
dtree.on("node('depart')", function (param) {
$('#DepartmentID').val(param.param.nodeId);
});
dtree.render({
elem: "#role",
initLevel: "2", // 默认展开层级为1
line: true, // 有线树
ficon: ["1", "-1"], // 设定一级图标样式。0表示方形加减图标8表示小圆点图标
icon: ["0", "2"], // 设定二级图标样式。0表示文件夹图标5表示叶子图标
method: 'POST',
url: "/system/role/dtree",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
select: true,
selectInitVal: $('#RoleID').val()
});
// 单击节点 监听事件
dtree.on("node('role')", function (param) {
$('#RoleID').val(param.param.nodeId);
});
getDepartmentTree();
getRoleTree();
// 表单提交
form.on('submit(save)', function (data) {
@@ -232,6 +205,80 @@
window.parent.layer.close(parent.layer.getFrameIndex(window.name));
}
});
function getDepartmentTree() {
$.ajax({
url: "/system/department/tree?type=xmselect",
type: 'post',
dataType: 'json',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
success: function (res) {
xmSelect.render({
el: '#departTree',
// 工具栏
toolbar: {
show: true
},
radio: true,
clickClose: true,
tips: '请选择父级',
filterable: true,
data: res,
name: 'DepartmentID',
initValue: ['{{.Item.DepartmentID}}'],
tree: {
show: true,
//非严格模式
strict: false,
//默认展开节点的数组, 为 true 时, 展开所有节点
expandedKeys: [1],
},
on: function (data) { },
});
},
error: function (err) {
// 处理请求错误
console.log('请求出错:', err);
}
});
}
function getRoleTree() {
$.ajax({
url: "/system/role/tree?type=xmselect",
type: 'post',
dataType: 'json',
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
success: function (res) {
xmSelect.render({
el: '#roleTree',
// 工具栏
toolbar: {
show: true
},
radio: true,
clickClose: true,
tips: '请选择父级',
filterable: true,
data: res,
name: 'RoleID',
initValue: ['{{.Item.RoleID}}'],
tree: {
show: true,
//非严格模式
strict: false,
//默认展开节点的数组, 为 true 时, 展开所有节点
expandedKeys: [1],
},
on: function (data) { },
});
},
error: function (err) {
// 处理请求错误
console.log('请求出错:', err);
}
});
}
});
</script>
{{end}}

View File

@@ -1,95 +1,79 @@
{{template "header"}}
<div class="layui-row layui-col-space15">
<div class="layui-collapse">
<div class="layui-colla-item">
<div class="layui-colla-title">查询</div>
<div class="layui-colla-content layui-show">
<div class="layui-card">
<div class="layui-card-body layui-bzw-table">
<form class="layui-form" action="">
{{.CsrfTokenField}}
<div class="layui-form-item">
<div class="layui-form-item layui-inline">
<select id="searchStatus">
<option value="0">正常</option>
<option value="-1">删除</option>
<option value="9999">全部</option>
</select>
</div>
<div class="layui-form-item layui-inline">
<select id="searchName">
<option value="userName">名称</option>
</select>
</div>
<div class="layui-form-item layui-inline">
<input type="text" id="searchKey" placeholder=""
class="layui-input layui-form-group-input">
</div>
<div class="layui-form-item layui-inline">
<button type="button" class="pear-btn pear-btn-md pear-btn-primary" lay-submit
lay-filter="user-query">
<i class="layui-icon layui-icon-search"></i>
查询
</button>
<button type="reset" class="pear-btn pear-btn-md" lay-submit
lay-filter="user-reset">
<i class="layui-icon layui-icon-refresh"></i>
重置
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 工具栏 -->
<script id="toolbar" type="text/html">
{{ genBtn .AuthorizeMenus "add"}}
<button type="button" lay-event="search" lay-on="search" class="layui-btn layui-btn-primary layui-btn-sm">
<i class="layui-icon layui-icon-search"></i>
</button>
</script>
<div class="layui-card" style="margin-top: 15px;">
<div class="layui-card-body">
<table id="tablelist" lay-filter="tablelist"></table>
</div>
</div>
<script type="text/html" id="actionBox">
{{ genLink .AuthorizeMenus "edit"}}
</script>
<div class="search-layer" id="search-layer" style="display: none;">
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">状态</label>
<select name="status" id="status">
{{range.Statuses}}
<option value="{{.Value}}">{{.Name}}</option>
{{end}}
</select>
</div>
</div>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">编号</label>
<input type="text" name="id" id="id" placeholder="请输入编号" autocomplete="off" class="layui-input">
</div>
</div>
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">邮箱</label>
<input type="text" name="email" id="email" placeholder="请输入邮箱" autocomplete="off" class="layui-input">
</div>
</div>
</div>
<div class="layui-form layui-row">
<div class="layui-col-xs12 layui-col-sm12 layui-col-md4">
<div class="layui-form-column">
<label class="tips">用户名</label>
<input type="text" name="username" id="username" placeholder="请输入用户名" autocomplete="off"
class="layui-input">
</div>
</div>
</div>
</div>
<div class="layui-panel">
<table id="tablelist" lay-filter="tablelist"></table>
</div>
{{define "js"}}
<script>
layui.use(['table', 'form', 'jquery', 'util'], function () {
layui.use(['jquery', 'table', 'form', 'util'], function () {
let $ = layui.jquery;
let table = layui.table;
let form = layui.form;
let $ = layui.jquery;
let util = layui.util;
loadList();
toolbar();
tableActionTool();
search();
// 加载列表
function loadList() {
table.render({
elem: '#tablelist',
url: "/system/user/list",
method: "POST",
headers: { 'X-CSRF-Token': $('#csrf_token').val() },
where: getQueryParams(),
height: 'full',
height: function () {
return $(window).height() - 22;
},
page: true,
limit: 15,
limits: [15, 30, 45, 60, 75, 90],
cols: [[
{ field: 'email', title: '邮箱', align: 'left', width: 180 },
{ field: 'email', title: '邮箱', align: 'left', width: 180, fixed: 'left' },
{ field: 'username', title: '用户名', align: 'left', width: 100 },
{
field: 'avatar', title: '头像', align: 'center', width: 90, templet: function (d) {
@@ -97,7 +81,7 @@
if (d.avatar === '/statics/admin/images/avatar.jpg') {
return '<img src="/statics/admin/images/avatar.jpg" width=30 height=30 />';
}
return '<img src="https://school-1251542740.cos.ap-shanghai.myqcloud.com' + d.avatar + '" width=30 height=30 />';
return '<img src="' + d.avatar + '" width=30 height=30 />';
}
},
{ field: 'department_name', title: '部门', align: 'left', width: 100 },
@@ -123,11 +107,11 @@
return '';
}
},
{ title: '操作', toolbar: '#actionBox', align: 'center', width: 100 },
{ field: 'created_at', title: '创建时间', align: 'center', width: 160, templet: function (d) { return !d.created_at ? '' : util.toDateString(d.created_at) } },
{ field: 'updated_at', title: '更新时间', align: 'center', width: 160, templet: function (d) { return !d.updated_at ? '' : util.toDateString(d.updated_at) } },
{ title: '操作', toolbar: '#actionBox', align: 'center', width: 100, fixed: 'right' },
]],
skin: 'line',
skin: 'grid',
toolbar: '#toolbar',
defaultToolbar: [{
title: '刷新',
@@ -139,13 +123,11 @@
limitName: 'rows'
}
});
}
// 工具栏
function toolbar() {
table.on('toolbar(tablelist)', function (obj) {
switch (obj.event) {
case 'add': add(); break;
case 'search': search(); break;
case 'refresh': refresh(); break;
}
});
@@ -155,18 +137,45 @@
type: 2,
title: '新增',
shade: 0.1,
area: ['95%', '95%'],
area: ['99%', '98%'],
content: "/system/user/add"
});
}
function search() {
layer.open({
type: 1,
offset: '20px',
title: '搜索',
content: $('#search-layer'), // 捕获的元素
shade: 0.1,
shadeClose: false,
scrollbar: false,
resize: false,
move: false,
skin: 'search-layer-open',
area: ['50%', '350px'],
btn: ['搜索', '重置'],
btn1: function (index, layero) {
console.log('搜索');
search_btn();
layer.close(index);
},
btn2: function (index, layero) {
$('#id').val('');
$('#email').val('');
$('#username').val('');
$('#status').val(9999);
form.render('select');
return false;
}
});
}
function refresh() {
table.reload('tablelist');
}
}
// 表格项操作按钮
function tableActionTool() {
table.on('tool(tablelist)', function (obj) {
switch (obj.event) {
case 'edit': edit(obj); break;
@@ -178,7 +187,7 @@
type: 2,
title: '修改',
shade: 0.1,
area: ['95%', '95%'],
area: ['99%', '98%'],
content: "/system/user/edit?id=" + obj.data['id']
});
}
@@ -204,20 +213,19 @@
layer.close(index); // 关闭弹窗
});
}
}
// 搜索条件
function getQueryParams() {
return {
SearchStatus: $('#searchStatus').val(),
SearchName: $('#searchName').val(),
SearchKey: $('#searchKey').val()
status: $('#status').val(),
name: $('#username').val(),
email: $('#email').val(),
id: $('#id').val()
};
}
// 搜索
function search() {
form.on('submit(user-query)', function (data) {
function search_btn() {
table.reload('tablelist', {
where: getQueryParams(),
page: {
@@ -225,7 +233,6 @@
}
})
return false;
});
}
});
</script>