package system import ( "context" "errors" "strconv" "time" "management/internal/erpserver/model/dto" "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/sqldb" "github.com/google/uuid" "go.uber.org/zap" ) type userService struct { *v1.Service repo system.UserRepository roleService v1.RoleService departmentService v1.DepartmentService loginLogService v1.LoginLogService } func NewUserService( service *v1.Service, repo system.UserRepository, roleService v1.RoleService, departmentService v1.DepartmentService, loginLogService v1.LoginLogService, ) v1.UserService { return &userService{ Service: service, repo: repo, roleService: roleService, departmentService: departmentService, loginLogService: loginLogService, } } func (s *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 = s.repo.Create(ctx, user) if err != nil { if errors.Is(err, sqldb.ErrDBDuplicatedEntry) { return errors.New("用户已经存在") } return err } return nil } func (s *userService) Update(ctx context.Context, req *form.User) error { user, err := s.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() } _, err = s.repo.Update(ctx, user) return err } func (s *userService) All(ctx context.Context) ([]*system.User, error) { return s.repo.All(ctx) } func (s *userService) List(ctx context.Context, q dto.SearchDto) ([]*system.User, int64, error) { count, err := s.repo.Count(ctx, q) if err != nil { return nil, 0, err } res, err := s.repo.List(ctx, q) if err != nil { return nil, 0, err } for _, user := range res { user.Role, _ = s.roleService.Get(ctx, user.RoleID) user.Department, _ = s.departmentService.Get(ctx, user.DepartmentID) } return res, count, nil } func (s *userService) Get(ctx context.Context, id int32) (*system.User, error) { return s.repo.Get(ctx, id) } func (s *userService) GetByEmail(ctx context.Context, email string) (*system.User, error) { return s.repo.GetByEmail(ctx, email) } func (s *userService) XmSelect(ctx context.Context) ([]*view.XmSelect, error) { all, err := s.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 (s *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 := s.login(ctx, req) if err != nil { if err := s.loginLogService.Create(ctx, l.SetMessage(err.Error())); err != nil { s.Log.Error(err.Error(), err, zap.Any("login_log", l)) } return err } if err := s.loginLogService.Create(ctx, l.SetOk("登录成功")); err != nil { s.Log.Error(err.Error(), err, zap.Any("login_log", l)) } return nil } func (s *userService) login(ctx context.Context, req *form.Login) (*system.User, error) { user, err := s.repo.GetByEmail(ctx, req.Email) if err != nil { return nil, err } err = crypto.BcryptComparePassword(user.HashedPassword, req.Password+user.Salt) if err != nil { return nil, errors.New("账号或密码错误") } user.Role, err = s.roleService.Get(ctx, user.RoleID) if err != nil { return nil, err } if user.Role == nil || user.Role.ID == 0 { return nil, errors.New("账号没有配置角色, 请联系管理员") } // 登陆成功 err = s.loginSuccess(ctx, user, req) if err != nil { return nil, err } return user, nil } func (s *userService) loginSuccess(ctx context.Context, user *system.User, req *form.Login) error { return s.Session.PutUser(ctx, know.StoreName, system.AuthorizeUser{ ID: user.ID, Uuid: user.Uuid, Email: user.Email, Username: user.Username, Avatar: user.Avatar, RoleID: user.Role.ID, RoleName: user.Role.DisplayName, OS: req.Os, IP: req.Ip, Browser: req.Browser, }) }