This commit is contained in:
2025-04-14 15:28:51 +08:00
parent f100427f8b
commit 371b89ee8d
93 changed files with 3757 additions and 1038 deletions

View File

@@ -0,0 +1,30 @@
package common
import (
v1 "management/internal/erpserver/service/v1"
"github.com/mojocn/base64Captcha"
)
type captchaService struct{}
var _ v1.CaptchaService = (*captchaService)(nil)
func NewCaptchaService() *captchaService {
return &captchaService{}
}
var captchaStore base64Captcha.Store = base64Captcha.DefaultMemStore
func (b *captchaService) Generate(height int, width int, length int, maxSkew float64, dotCount int) (id, b64s, answer string, err error) {
driver := base64Captcha.NewDriverDigit(height, width, length, maxSkew, dotCount)
// driver := base64Captcha.NewDriverString(config.File.Captcha.ImgHeight,
// config.File.Captcha.ImgWidth,
// 6, 1, keyLong, source, nil, nil, nil)
cp := base64Captcha.NewCaptcha(driver, captchaStore)
return cp.Generate()
}
func (b *captchaService) Verify(id, answer string, clear bool) bool {
return captchaStore.Verify(id, answer, clear)
}

View File

@@ -0,0 +1,102 @@
package v1
import (
"context"
"time"
"management/internal/db/model/dto"
"management/internal/erpserver/model/form"
"management/internal/erpserver/model/system"
"management/internal/erpserver/model/view"
)
type CaptchaService interface {
Generate(height int, width int, length int, maxSkew float64, dotCount int) (id, b64s, answer string, err error)
Verify(id, answer string, clear bool) bool
}
type ConfigService interface {
Create(ctx context.Context, obj *system.Config) error
Update(ctx context.Context, obj *system.Config) error
Get(ctx context.Context, id int32) (*system.Config, error)
List(ctx context.Context, q dto.SearchDto) ([]*system.Config, int64, error)
Pear(ctx context.Context) (*dto.PearConfig, error)
}
type UserService interface {
Create(ctx context.Context, req *form.User) error
Update(ctx context.Context, req *form.User) error
All(ctx context.Context) ([]*system.User, error)
List(ctx context.Context, q dto.SearchDto) ([]*system.User, int64, error)
Get(ctx context.Context, id int32) (*system.User, error)
XmSelect(ctx context.Context) ([]*view.XmSelect, error)
Login(ctx context.Context, req *form.Login) error
}
type LoginLogService interface {
Create(ctx context.Context, req *system.LoginLog) error
List(ctx context.Context, q dto.SearchDto) ([]*system.LoginLog, int64, error)
LoginLatestTime(ctx context.Context, email string) time.Time
LoginCount(ctx context.Context, email string) int64
}
type AuditLogService interface {
Create(ctx context.Context, req *system.AuditLog) error
List(ctx context.Context, q dto.SearchDto) ([]*system.AuditLog, int64, error)
}
type RoleService interface {
Create(ctx context.Context, req *form.Role) error
Update(ctx context.Context, req *form.Role) error
Get(ctx context.Context, id int32) (*system.Role, error)
All(ctx context.Context) ([]*system.Role, error)
List(ctx context.Context, q dto.SearchDto) ([]*system.Role, int64, error)
RefreshCache(ctx context.Context) error
RebuildParentPath(ctx context.Context) error
Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error)
XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error)
}
type DepartmentService interface {
Create(ctx context.Context, req *form.Department) error
Update(ctx context.Context, req *form.Department) error
Get(ctx context.Context, id int32) (*system.Department, error)
All(ctx context.Context) ([]*system.Department, error)
List(ctx context.Context, q dto.SearchDto) ([]*system.Department, int64, error)
RefreshCache(ctx context.Context) error
RebuildParentPath(ctx context.Context) error
Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error)
XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error)
}
type MenuService interface {
Create(ctx context.Context, req *system.Menu) error
Update(ctx context.Context, req *system.Menu) error
Get(ctx context.Context, id int32) (*system.Menu, error)
GetByUrl(ctx context.Context, url string) (*system.Menu, error)
All(ctx context.Context) ([]*system.Menu, error)
ListMenuTree(ctx context.Context) ([]*view.MenuTree, error)
ListByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error)
SetListByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error)
ListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error)
SetListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error)
OwerMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error)
SetOwerMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error)
MenuViewData(ctx context.Context, roleID int32) ([]*dto.SetMenuDto, error)
SetRoleMenu(ctx context.Context, roleID int32, rms []*system.RoleMenu) error
RefreshCache(ctx context.Context) error
RebuildParentPath(ctx context.Context) error
Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error)
XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error)
}
type RoleMenuService interface {
Create(ctx context.Context, req []*system.RoleMenu) error
DeleteByRoleID(ctx context.Context, roleID int32) error
ListByRoleID(ctx context.Context, roleID int32) ([]*system.RoleMenu, error)
}

View File

@@ -0,0 +1,29 @@
package system
import (
"context"
"management/internal/db/model/dto"
"management/internal/erpserver/model/system"
v1 "management/internal/erpserver/service/v1"
)
type auditLogService struct {
repo system.AuditLogRepository
}
var _ v1.AuditLogService = (*auditLogService)(nil)
func NewAuditLogService(repo system.AuditLogRepository) *auditLogService {
return &auditLogService{
repo: repo,
}
}
func (b *auditLogService) Create(ctx context.Context, req *system.AuditLog) error {
return b.repo.Create(ctx, req)
}
func (b *auditLogService) List(ctx context.Context, q dto.SearchDto) ([]*system.AuditLog, int64, error) {
return b.repo.List(ctx, q)
}

View File

@@ -0,0 +1,69 @@
package system
import (
"context"
"encoding/json"
"time"
"management/internal/db/model/dto"
"management/internal/erpserver/model/system"
v1 "management/internal/erpserver/service/v1"
"management/internal/pkg/know"
"management/internal/pkg/know/pearadmin"
"management/internal/pkg/redis"
)
type configService struct {
repo system.ConfigRepository
redis redis.RedisCache
}
var _ v1.ConfigService = (*configService)(nil)
func NewConfigService(repo system.ConfigRepository, redis redis.RedisCache) *configService {
return &configService{
repo: repo,
redis: redis,
}
}
func (s *configService) Create(ctx context.Context, obj *system.Config) error {
return s.repo.Create(ctx, obj)
}
func (s *configService) Update(ctx context.Context, obj *system.Config) error {
return s.repo.Update(ctx, obj)
}
func (s *configService) Get(ctx context.Context, id int32) (*system.Config, error) {
return s.repo.Get(ctx, id)
}
func (s *configService) List(ctx context.Context, q dto.SearchDto) ([]*system.Config, int64, error) {
return s.repo.List(ctx, q)
}
func (s *configService) Pear(ctx context.Context) (*dto.PearConfig, error) {
// 判断redis是否存储
key := know.GetManageKey(ctx, know.PearAdmin)
bs, err := s.redis.GetBytes(ctx, key)
if err == nil {
var res *dto.PearConfig
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
conf, err := s.repo.GetByKey(ctx, pearadmin.PearKey)
if err != nil {
return nil, err
}
var pear dto.PearConfig
if err := json.Unmarshal(conf.Value, &pear); err != nil {
return nil, err
}
_ = s.redis.Set(ctx, key, conf.Value, time.Hour*6)
return &pear, nil
}

View File

@@ -0,0 +1,207 @@
package system
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/form"
"management/internal/erpserver/model/system"
"management/internal/erpserver/model/view"
v1 "management/internal/erpserver/service/v1"
"management/internal/pkg/convertor"
"management/internal/pkg/know"
"management/internal/pkg/redis"
)
type departmentService struct {
repo system.DepartmentRepository
}
var _ v1.DepartmentService = (*departmentService)(nil)
func NewDepartmentService(repo system.DepartmentRepository) *departmentService {
return &departmentService{
repo: repo,
}
}
func (s *departmentService) Create(ctx context.Context, req *form.Department) error {
parent := &system.Department{
ID: 0,
ParentID: 0,
ParentPath: ",0,",
}
if *req.ParentID > 0 {
var err error
parent, err = s.Get(ctx, *req.ParentID)
if err != nil {
return errors.New("父级节点错误")
}
}
var order int32 = 6666
if *req.Sort > 0 {
order = *req.Sort
}
arg := &system.Department{
Name: req.Name,
ParentID: parent.ID,
ParentPath: convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID)),
Status: *req.Status,
Sort: order,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err := s.repo.Create(ctx, arg)
if err != nil {
if db.IsUniqueViolation(err) {
return errors.New("部门已存在")
}
return err
}
return nil
}
func (s *departmentService) Update(ctx context.Context, req *form.Department) error {
parent := &system.Department{
ID: 0,
ParentID: 0,
ParentPath: ",0,",
}
if *req.ParentID > 0 {
var err error
parent, err = s.Get(ctx, *req.ParentID)
if err != nil {
return errors.New("父级节点错误")
}
}
depart, err := s.Get(ctx, *req.ID)
if err != nil {
return err
}
var order int32 = 6666
if *req.Sort > 0 {
order = *req.Sort
}
depart.Name = req.Name
depart.ParentID = parent.ID
depart.ParentPath = convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID))
depart.Status = *req.Status
depart.Sort = order
depart.UpdatedAt = time.Now()
return s.repo.Update(ctx, depart)
}
func (s *departmentService) Get(ctx context.Context, id int32) (*system.Department, error) {
return s.repo.Get(ctx, id)
}
func (s *departmentService) All(ctx context.Context) ([]*system.Department, error) {
key := know.GetManageKey(ctx, know.AllDepartments)
bs, err := redis.GetBytes(ctx, key)
if err == nil {
var res []*system.Department
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
res, err := s.repo.All(ctx)
if err != nil {
return nil, err
}
bs, err = json.Marshal(res)
if err != nil {
return nil, err
}
_ = redis.Set(ctx, key, bs, time.Hour*6)
return res, nil
}
func (s *departmentService) List(ctx context.Context, q dto.SearchDto) ([]*system.Department, int64, error) {
return s.repo.List(ctx, q)
}
func (s *departmentService) RefreshCache(ctx context.Context) error {
key := know.GetManageKey(ctx, know.AllDepartments)
res, err := s.All(ctx)
if err != nil {
return err
}
b, err := json.Marshal(res)
if err != nil {
return err
}
_ = redis.Set(ctx, key, b, time.Hour*6)
return nil
}
func (s *departmentService) RebuildParentPath(ctx context.Context) error {
return s.repo.RebuildParentPath(ctx)
}
func (s *departmentService) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toTree(id, all), nil
}
func (s *departmentService) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toXmSelectTree(id, all), nil
}
func (s *departmentService) toTree(parentId int32, data []*system.Department) []*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 = s.toTree(v.ID, data)
if v.ParentID == 0 {
item.Spread = true
}
res = append(res, &item)
}
}
return res
}
func (s *departmentService) toXmSelectTree(parentId int32, data []*system.Department) []*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: s.toXmSelectTree(v.ID, data),
}
res = append(res, &item)
}
}
return res
}

View File

@@ -0,0 +1,46 @@
package system
import (
"context"
"time"
"management/internal/db/model/dto"
"management/internal/erpserver/model/system"
v1 "management/internal/erpserver/service/v1"
)
type loginLogService struct {
repo system.LoginLogRepository
}
var _ v1.LoginLogService = (*loginLogService)(nil)
func NewLoginLogService(repo system.LoginLogRepository) *loginLogService {
return &loginLogService{
repo: repo,
}
}
func (s *loginLogService) Create(ctx context.Context, req *system.LoginLog) error {
return s.repo.Create(ctx, req)
}
func (s *loginLogService) List(ctx context.Context, q dto.SearchDto) ([]*system.LoginLog, int64, error) {
return s.repo.List(ctx, q)
}
func (s *loginLogService) LoginLatestTime(ctx context.Context, email string) time.Time {
log, err := s.repo.GetLatest(ctx, email)
if err != nil {
return time.Time{}
}
return log.CreatedAt
}
func (s *loginLogService) LoginCount(ctx context.Context, email string) int64 {
count, err := s.repo.Count(ctx, email)
if err != nil {
return 0
}
return count
}

View File

@@ -0,0 +1,457 @@
package system
import (
"context"
"encoding/json"
"strconv"
"strings"
"time"
"management/internal/db/model/dto"
"management/internal/erpserver/model/system"
"management/internal/erpserver/model/view"
"management/internal/erpserver/repository"
v1 "management/internal/erpserver/service/v1"
"management/internal/pkg/know"
"management/internal/pkg/redis"
)
type menuService struct {
redis redis.RedisCache
store repository.Store
repo system.MenuRepository
rolesvc v1.RoleService
rolemenusvc v1.RoleMenuService
}
var _ v1.MenuService = (*menuService)(nil)
func NewMenuService(redis redis.RedisCache, store repository.Store, repo system.MenuRepository, rolesvc v1.RoleService, rolemenusvc v1.RoleMenuService) *menuService {
return &menuService{
redis: redis,
store: store,
repo: repo,
rolesvc: rolesvc,
rolemenusvc: rolemenusvc,
}
}
func (s *menuService) Create(ctx context.Context, req *system.Menu) error {
return s.repo.Create(ctx, req)
}
func (s *menuService) Update(ctx context.Context, req *system.Menu) error {
return s.repo.Update(ctx, req)
}
func (s *menuService) Get(ctx context.Context, id int32) (*system.Menu, error) {
return s.repo.Get(ctx, id)
}
func (s *menuService) GetByUrl(ctx context.Context, url string) (*system.Menu, error) {
return s.repo.GetByUrl(ctx, url)
}
func (s *menuService) All(ctx context.Context) ([]*system.Menu, error) {
key := know.GetManageKey(ctx, know.AllMenus)
b, err := s.redis.GetBytes(ctx, key)
if err == nil {
var res []*system.Menu
if err := json.Unmarshal(b, &res); err == nil {
return res, nil
}
}
res, err := s.repo.All(ctx)
if err != nil {
return nil, err
}
b, err = json.Marshal(res)
if err != nil {
return nil, err
}
_ = s.redis.Set(ctx, key, b, time.Hour*6)
return res, nil
}
func (s *menuService) ListMenuTree(ctx context.Context) ([]*view.MenuTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return toListTree(0, all), nil
}
func (s *menuService) ListByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) {
key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
bs, err := s.redis.GetBytes(ctx, key)
if err == nil {
var res []*dto.OwnerMenuDto
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
return s.SetListByRoleID(ctx, roleID)
}
func (s *menuService) SetListByRoleID(ctx context.Context, roleID int32) ([]*dto.OwnerMenuDto, error) {
key := know.GetManageKey(ctx, know.OwnerMenus, roleID)
menus, err := s.listByRoleID(ctx, roleID)
if err != nil {
return nil, err
}
res := toOwnerMenuDto(menus)
b, err := json.Marshal(res)
if err != nil {
return nil, err
}
_ = s.redis.Set(ctx, key, b, time.Hour*6)
return res, nil
}
func (s *menuService) ListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
key := know.GetManageKey(ctx, know.OwnerMenusMap, roleID)
bs, err := s.redis.GetBytes(ctx, key)
if err == nil {
var res map[string]*dto.OwnerMenuDto
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
return s.SetListByRoleIDToMap(ctx, roleID)
}
func (s *menuService) SetListByRoleIDToMap(ctx context.Context, roleID int32) (map[string]*dto.OwnerMenuDto, error) {
key := know.GetManageKey(ctx, know.OwnerMenusMap, roleID)
menus, err := s.listByRoleID(ctx, roleID)
if err != nil {
return nil, err
}
res := toOwnerMenuDtoMap(menus)
b, err := json.Marshal(res)
if err != nil {
return nil, err
}
_ = s.redis.Set(ctx, key, b, time.Hour*6)
return res, nil
}
func (s *menuService) OwerMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) {
key := know.GetManageKey(ctx, know.AdminMenus, roleID)
bs, err := s.redis.GetBytes(ctx, key)
if err == nil {
var res []*dto.MenuUIDto
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
return s.SetOwerMenus(ctx, roleID)
}
func (s *menuService) SetOwerMenus(ctx context.Context, roleID int32) ([]*dto.MenuUIDto, error) {
key := know.GetManageKey(ctx, know.AdminMenus, roleID)
menus, err := s.listByRoleID(ctx, roleID)
if err != nil {
return nil, err
}
res := convertToUITree(menus, 0)
b, err := json.Marshal(res)
if err != nil {
return nil, err
}
_ = s.redis.Set(ctx, key, b, time.Hour*6)
return res, nil
}
func (s *menuService) MenuViewData(ctx context.Context, roleID int32) ([]*dto.SetMenuDto, error) {
// 获取该用户已经有的权限
hs, err := s.listByRoleID(ctx, roleID)
if err != nil {
return nil, err
}
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return toSetMenuTree(all, hs, 0), nil
}
func (s *menuService) SetRoleMenu(ctx context.Context, roleID int32, rms []*system.RoleMenu) error {
// 开启事务
return s.store.TX(ctx, func(ctx context.Context) error {
// 先删除该角色的所有权限
err := s.rolemenusvc.DeleteByRoleID(ctx, roleID)
if err != nil {
return err
}
// 再添加该角色的所有权限
return s.rolemenusvc.Create(ctx, rms)
})
}
func (s *menuService) RefreshCache(ctx context.Context) error {
key := know.GetManageKey(ctx, know.AllMenus)
res, err := s.All(ctx)
if err != nil {
return err
}
b, err := json.Marshal(res)
if err != nil {
return err
}
_ = redis.Set(ctx, key, b, time.Hour*6)
return nil
}
func (s *menuService) RebuildParentPath(ctx context.Context) error {
return s.repo.RebuildParentPath(ctx)
}
func (s *menuService) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toTree(id, all), nil
}
func (s *menuService) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toXmSelectTree(id, all), nil
}
// listByRoleID 获取该角色所拥有的菜单集合
func (s *menuService) listByRoleID(ctx context.Context, roleID int32) ([]*system.Menu, error) {
role, err := s.rolesvc.Get(ctx, roleID)
if err != nil {
return nil, err
}
res, err := s.repo.All(ctx)
if err != nil {
return nil, err
}
if role.Vip {
return res, nil
}
// 通过角色获取所拥有的权限
roleMenus, err := s.rolemenusvc.ListByRoleID(ctx, roleID)
if err != nil {
return nil, err
}
return findMenu(roleMenus, res), nil
}
func (s *menuService) toTree(parentId int32, data []*system.Menu) []*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 = s.toTree(v.ID, data)
if v.ParentID == 0 {
item.Spread = true
}
res = append(res, &item)
}
}
return res
}
func (s *menuService) toXmSelectTree(parentId int32, data []*system.Menu) []*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: s.toXmSelectTree(v.ID, data),
}
res = append(res, &item)
}
}
return res
}
func findMenu(rms []*system.RoleMenu, ms []*system.Menu) []*system.Menu {
var res []*system.Menu
for _, rm := range rms {
for _, m := range ms {
if rm.MenuID == m.ID {
res = append(res, m)
}
}
}
return res
}
func toOwnerMenuDto(ms []*system.Menu) []*dto.OwnerMenuDto {
var res []*dto.OwnerMenuDto
for _, m := range ms {
res = append(res, &dto.OwnerMenuDto{
ID: m.ID,
DisplayName: m.DisplayName,
Url: m.Url,
ParentID: m.ParentID,
Avatar: m.Avatar,
Style: m.Style,
IsList: m.IsList,
})
}
return res
}
func toOwnerMenuDtoMap(ms []*system.Menu) map[string]*dto.OwnerMenuDto {
res := make(map[string]*dto.OwnerMenuDto)
for _, m := range ms {
res[m.Url] = &dto.OwnerMenuDto{
ID: m.ID,
DisplayName: m.DisplayName,
Url: m.Url,
ParentID: m.ParentID,
Avatar: m.Avatar,
Style: m.Style,
IsList: m.IsList,
}
}
return res
}
func convertToUITree(data []*system.Menu, parentID int32) []*dto.MenuUIDto {
var root []*dto.MenuUIDto
for _, item := range data {
if item.ParentID == parentID {
if item.IsList {
temp := &dto.MenuUIDto{
ID: strings.ToLower(item.Url),
Title: item.DisplayName,
Icon: item.Avatar,
Type: 1,
OpenType: "_iframe",
// OpenType: "_component",
Href: item.Url,
}
root = append(root, temp)
} else {
temp := &dto.MenuUIDto{
ID: strconv.Itoa(int(item.ID)),
Title: item.DisplayName,
Icon: item.Avatar,
Type: 0,
}
temp.Children = convertToUITree(data, item.ID)
root = append(root, temp)
}
}
}
return root
}
func toSetMenuTree(data []*system.Menu, ids []*system.Menu, parentID int32) []*dto.SetMenuDto {
var res []*dto.SetMenuDto
for _, v := range data {
if v.ParentID == parentID {
isSelect := hasValueInArray(ids, v.ID)
if v.IsList {
item := dto.SetMenuDto{
ID: v.ID,
Name: v.DisplayName,
Link: v.Type,
IsList: v.IsList,
IsSelect: isSelect,
}
item.Items = []*dto.SetMenuDto{
{
ID: v.ID,
Name: "列表",
Link: "btn",
IsList: false,
IsSelect: isSelect,
Items: toSetMenuTree(data, ids, v.ID),
},
}
item.Items = append(item.Items, toSetMenuTree(data, ids, v.ID)...)
res = append(res, &item)
} else {
item := dto.SetMenuDto{
ID: v.ID,
Name: v.DisplayName,
Link: v.Type,
IsList: v.IsList,
IsSelect: isSelect,
Items: toSetMenuTree(data, ids, v.ID),
}
res = append(res, &item)
}
}
}
return res
}
func hasValueInArray(data []*system.Menu, id int32) bool {
for _, v := range data {
if v.ID == id {
return true
}
}
return false
}
func toListTree(parentId int32, data []*system.Menu) []*view.MenuTree {
var res []*view.MenuTree
for _, v := range data {
if v.ParentID == parentId {
item := view.MenuTree{}
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 = toListTree(v.ID, data)
res = append(res, &item)
}
}
return res
}

View File

@@ -0,0 +1,210 @@
package system
import (
"context"
"encoding/json"
"errors"
"fmt"
"strconv"
"time"
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/form"
"management/internal/erpserver/model/system"
"management/internal/erpserver/model/view"
v1 "management/internal/erpserver/service/v1"
"management/internal/pkg/convertor"
"management/internal/pkg/know"
"management/internal/pkg/redis"
)
type roleService struct {
repo system.RoleRepository
}
var _ v1.RoleService = (*roleService)(nil)
func NewRoleService(repo system.RoleRepository) *roleService {
return &roleService{
repo: repo,
}
}
func (s *roleService) Create(ctx context.Context, req *form.Role) error {
parent := &system.Role{
ID: 0,
ParentID: 0,
ParentPath: ",0,",
}
if *req.ParentID > 0 {
var err error
parent, err = s.repo.Get(ctx, *req.ParentID)
if err != nil {
return errors.New("父级节点错误")
}
}
var order int32 = 6666
if *req.Sort > 0 {
order = *req.Sort
}
arg := &system.Role{
Name: req.Name,
DisplayName: req.DisplayName,
ParentID: parent.ID,
ParentPath: convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID)),
Vip: false,
Status: *req.Status,
Sort: order,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err := s.repo.Create(ctx, arg)
if err != nil {
if db.IsUniqueViolation(err) {
return errors.New("角色名称已存在")
}
return err
}
return nil
}
func (s *roleService) Update(ctx context.Context, req *form.Role) error {
parent := &system.Role{
ID: 0,
ParentID: 0,
ParentPath: ",0,",
}
if *req.ParentID > 0 {
var err error
parent, err = s.repo.Get(ctx, *req.ParentID)
if err != nil {
return errors.New("父级节点错误")
}
}
role, err := s.repo.Get(ctx, *req.ID)
if err != nil {
return err
}
var order int32 = 6666
if *req.Sort > 0 {
order = *req.Sort
}
role.DisplayName = req.DisplayName
role.Status = *req.Status
role.ParentID = parent.ID
role.ParentPath = convertor.HandleParentPath(fmt.Sprintf("%s,%d,", parent.ParentPath, parent.ID))
role.Sort = order
role.UpdatedAt = time.Now()
err = s.repo.Update(ctx, role)
return err
}
func (s *roleService) Get(ctx context.Context, id int32) (*system.Role, error) {
return s.repo.Get(ctx, id)
}
func (s *roleService) All(ctx context.Context) ([]*system.Role, error) {
key := know.GetManageKey(ctx, know.AllRoles)
bs, err := redis.GetBytes(ctx, key)
if err == nil {
var res []*system.Role
if err := json.Unmarshal(bs, &res); err == nil {
return res, nil
}
}
res, err := s.repo.All(ctx)
if err != nil {
return nil, err
}
bs, err = json.Marshal(res)
if err != nil {
return nil, err
}
_ = redis.Set(ctx, key, bs, time.Hour*6)
return res, nil
}
func (s *roleService) List(ctx context.Context, q dto.SearchDto) ([]*system.Role, int64, error) {
return s.repo.List(ctx, q)
}
func (s *roleService) RefreshCache(ctx context.Context) error {
key := know.GetManageKey(ctx, know.AllRoles)
res, err := s.All(ctx)
if err != nil {
return err
}
b, err := json.Marshal(res)
if err != nil {
return err
}
_ = redis.Set(ctx, key, b, time.Hour*6)
return nil
}
func (s *roleService) RebuildParentPath(ctx context.Context) error {
return s.repo.RebuildParentPath(ctx)
}
func (s *roleService) Tree(ctx context.Context, id int32) ([]*view.LayuiTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toTree(id, all), nil
}
func (s *roleService) XmSelectTree(ctx context.Context, id int32) ([]*view.XmSelectTree, error) {
all, err := s.All(ctx)
if err != nil {
return nil, err
}
return s.toXmSelectTree(id, all), nil
}
func (s *roleService) toTree(parentId int32, data []*system.Role) []*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 = s.toTree(v.ID, data)
if v.ParentID == 0 {
item.Spread = true
}
res = append(res, &item)
}
}
return res
}
func (s *roleService) toXmSelectTree(parentId int32, data []*system.Role) []*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: s.toXmSelectTree(v.ID, data),
}
res = append(res, &item)
}
}
return res
}

View File

@@ -0,0 +1,32 @@
package system
import (
"context"
"management/internal/erpserver/model/system"
v1 "management/internal/erpserver/service/v1"
)
type roleMenuService struct {
repo system.RoleMenuRepository
}
var _ v1.RoleMenuService = (*roleMenuService)(nil)
func NewRoleMenuService(repo system.RoleMenuRepository) *roleMenuService {
return &roleMenuService{
repo: repo,
}
}
func (s *roleMenuService) Create(ctx context.Context, req []*system.RoleMenu) error {
return s.repo.Create(ctx, req)
}
func (s *roleMenuService) DeleteByRoleID(ctx context.Context, roleID int32) error {
return s.repo.DeleteByRoleID(ctx, roleID)
}
func (s *roleMenuService) ListByRoleID(ctx context.Context, roleID int32) ([]*system.RoleMenu, error) {
return s.repo.ListByRoleID(ctx, roleID)
}

View File

@@ -0,0 +1,203 @@
package system
import (
"context"
"encoding/json"
"errors"
"strconv"
"time"
"management/internal/db/model/dto"
db "management/internal/db/sqlc"
"management/internal/erpserver/model/form"
"management/internal/erpserver/model/system"
"management/internal/erpserver/model/view"
v1 "management/internal/erpserver/service/v1"
"management/internal/pkg/crypto"
"management/internal/pkg/know"
"management/internal/pkg/rand"
"management/internal/pkg/session"
"github.com/drhin/logger"
"github.com/google/uuid"
"go.uber.org/zap"
)
type userService struct {
session session.Session
log *logger.Logger
repo system.UserRepository
roleService v1.RoleService
loginLogService v1.LoginLogService
}
var _ v1.UserService = (*userService)(nil)
func NewUserService(session session.Session, log *logger.Logger, repo system.UserRepository, roleService v1.RoleService, loginLogService v1.LoginLogService) *userService {
return &userService{
session: session,
log: log,
repo: repo,
roleService: roleService,
loginLogService: loginLogService,
}
}
func (b *userService) Create(ctx context.Context, req *form.User) error {
salt, err := rand.String(10)
if err != nil {
return err
}
hashedPassword, err := crypto.BcryptHashPassword(req.Password + salt)
if err != nil {
return err
}
initTime, err := time.ParseInLocation(time.DateTime, "0001-01-01 00:00:00", time.Local)
if err != nil {
return err
}
user := &system.User{
Uuid: uuid.Must(uuid.NewV7()),
Email: req.Email,
Username: req.Username,
HashedPassword: hashedPassword,
Salt: salt,
Avatar: req.Avatar,
Gender: req.Gender,
DepartmentID: req.DepartmentID,
RoleID: req.RoleID,
Status: *req.Status,
ChangePasswordAt: initTime,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
err = b.repo.Create(ctx, user)
if err != nil {
if db.IsUniqueViolation(err) {
return errors.New("用户已经存在")
}
return err
}
return nil
}
func (b *userService) Update(ctx context.Context, req *form.User) error {
user, err := b.repo.Get(ctx, *req.ID)
if err != nil {
return err
}
user.Username = req.Username
user.Avatar = req.Avatar
user.Gender = req.Gender
user.DepartmentID = req.DepartmentID
user.RoleID = req.RoleID
user.Status = *req.Status
user.UpdatedAt = time.Now()
if req.ChangePassword == "on" {
hashedPassword, err := crypto.BcryptHashPassword(req.Password + user.Salt)
if err != nil {
return err
}
user.HashedPassword = hashedPassword
user.ChangePasswordAt = time.Now()
}
return b.repo.Update(ctx, user)
}
func (b *userService) All(ctx context.Context) ([]*system.User, error) {
return b.repo.All(ctx)
}
func (b *userService) List(ctx context.Context, q dto.SearchDto) ([]*system.User, int64, error) {
return b.repo.List(ctx, q)
}
func (b *userService) Get(ctx context.Context, id int32) (*system.User, error) {
return b.repo.Get(ctx, id)
}
func (b *userService) XmSelect(ctx context.Context) ([]*view.XmSelect, error) {
all, err := b.repo.All(ctx)
if err != nil || len(all) == 0 {
return nil, err
}
var res []*view.XmSelect
for _, user := range all {
res = append(res, &view.XmSelect{
Name: user.Username,
Value: strconv.Itoa(int(user.ID)),
})
}
return res, nil
}
func (b *userService) Login(ctx context.Context, req *form.Login) error {
l := system.NewLoginLog(req.Email, req.Os, req.Ip, req.Browser, req.Url, req.Referrer)
err := b.login(ctx, req)
if err != nil {
if err := b.loginLogService.Create(ctx, l.SetMessage(err.Error())); err != nil {
b.log.Error(err.Error(), err, zap.Any("login_log", l))
}
return err
}
if err := b.loginLogService.Create(ctx, l.SetOk("登录成功")); err != nil {
b.log.Error(err.Error(), err, zap.Any("login_log", l))
}
return nil
}
func (b *userService) login(ctx context.Context, req *form.Login) error {
user, err := b.repo.GetByEmail(ctx, req.Email)
if err != nil {
return err
}
err = crypto.BcryptComparePassword(user.HashedPassword, req.Password+user.Salt)
if err != nil {
return errors.New("账号或密码错误")
}
user.Role, err = b.roleService.Get(ctx, user.RoleID)
if err != nil {
return err
}
if user.Role == nil || user.Role.ID == 0 {
return errors.New("账号没有配置角色, 请联系管理员")
}
// 登陆成功
err = b.loginSuccess(ctx, user, req)
if err != nil {
return err
}
return nil
}
func (b *userService) loginSuccess(ctx context.Context, user *system.User, req *form.Login) error {
auth := dto.AuthorizeUser{
ID: user.ID,
Uuid: user.Uuid,
Email: user.Email,
Username: user.Username,
RoleID: user.Role.ID,
RoleName: user.Role.DisplayName,
OS: req.Os,
IP: req.Ip,
Browser: req.Browser,
}
gob, err := json.Marshal(auth)
if err != nil {
return err
}
b.session.Put(ctx, know.StoreName, gob)
return nil
}