package adminuser import ( "bytes" "encoding/csv" "fmt" "strings" "time" "hyapp-admin-server/internal/config" "hyapp-admin-server/internal/model" "hyapp-admin-server/internal/modules/shared" "hyapp-admin-server/internal/repository" "hyapp-admin-server/internal/security" ) const defaultInitialPassword = "Hyapp@123456" type AdminUserService struct { store *repository.Store cfg config.Config } type CreateUserInput struct { Username string Name string Team string Status string Password string MFAEnabled bool RoleIDs []uint } type UpdateUserInput struct { Name *string Team *string Status *string MFAEnabled *bool RoleIDs *[]uint } type UserStatusInput struct { Status string } type BatchUserStatusInput struct { IDs []uint Status string } type PasswordResult struct { Password string } type UserExport struct { FileName string Content []byte Count int } type MoneyScopeInput struct { AppCode string RegionID int64 } func NewService(store *repository.Store, cfg config.Config) *AdminUserService { return &AdminUserService{store: store, cfg: cfg} } func (s *AdminUserService) ListUsers(actor shared.Actor, options repository.ListOptions) ([]model.User, int64, error) { access, err := s.store.DataAccessForUser(actor.UserID) if err != nil { return nil, 0, err } return s.store.ListUsersWithAccess(options, access) } func (s *AdminUserService) CreateUser(input CreateUserInput) (*model.User, PasswordResult, error) { password := strings.TrimSpace(input.Password) if password == "" { password = defaultInitialPassword } hash, err := security.HashPassword(password) if err != nil { return nil, PasswordResult{}, err } user := model.User{ Username: strings.TrimSpace(input.Username), Name: strings.TrimSpace(input.Name), PasswordHash: hash, Team: strings.TrimSpace(input.Team), Status: shared.DefaultString(input.Status, model.UserStatusActive), MFAEnabled: input.MFAEnabled, } if err := s.store.CreateUser(&user, input.RoleIDs); err != nil { return nil, PasswordResult{}, err } created, err := s.store.FindUserByID(user.ID) if err != nil { return nil, PasswordResult{}, err } return created, PasswordResult{Password: password}, nil } func (s *AdminUserService) GetUser(id uint) (*model.User, error) { return s.store.FindUserByID(id) } func (s *AdminUserService) ListUserMoneyScopes(id uint) ([]model.UserMoneyScope, error) { return s.store.ListUserMoneyScopes(id) } func (s *AdminUserService) ReplaceUserMoneyScopes(id uint, input []MoneyScopeInput) ([]model.UserMoneyScope, error) { scopes := make([]model.UserMoneyScope, 0, len(input)) for _, item := range input { scopes = append(scopes, model.UserMoneyScope{ AppCode: strings.TrimSpace(item.AppCode), RegionID: item.RegionID, }) } if err := s.store.ReplaceUserMoneyScopes(id, scopes); err != nil { return nil, err } return s.store.ListUserMoneyScopes(id) } func (s *AdminUserService) UpdateUser(id uint, input UpdateUserInput) (*model.User, error) { updates := map[string]any{} if input.Name != nil { updates["name"] = strings.TrimSpace(*input.Name) } if input.Team != nil { updates["team"] = strings.TrimSpace(*input.Team) } if input.Status != nil { updates["status"] = strings.TrimSpace(*input.Status) } if input.MFAEnabled != nil { updates["mfa_enabled"] = *input.MFAEnabled } return s.store.UpdateUser(id, updates, input.RoleIDs) } func (s *AdminUserService) UpdateUserStatus(id uint, input UserStatusInput) (*model.User, error) { return s.store.UpdateUserStatus(id, input.Status) } func (s *AdminUserService) ResetUserPassword(id uint, password string) (PasswordResult, error) { value := strings.TrimSpace(password) if value == "" { value = defaultInitialPassword } if err := s.store.ResetUserPassword(id, value); err != nil { return PasswordResult{}, err } return PasswordResult{Password: value}, nil } func (s *AdminUserService) BatchUpdateUserStatus(input BatchUserStatusInput) error { return s.store.BatchUpdateUserStatus(input.IDs, input.Status) } func (s *AdminUserService) ExportUsers(actor shared.Actor, options repository.ListOptions) (UserExport, error) { access, err := s.store.DataAccessForUser(actor.UserID) if err != nil { return UserExport{}, err } users, err := s.store.ExportUsersWithAccess(options, access) if err != nil { return UserExport{}, err } var buf bytes.Buffer writer := csv.NewWriter(&buf) _ = writer.Write([]string{"ID", "账号", "姓名", "角色", "团队", "状态", "MFA", "最后登录"}) for _, user := range users { lastLogin := "" if user.LastLoginAtMS != nil { lastLogin = time.UnixMilli(*user.LastLoginAtMS).UTC().Format("2006-01-02 15:04:05") } _ = writer.Write([]string{ fmt.Sprintf("%d", user.ID), user.Username, user.Name, strings.Join(roleNames(user.Roles), "、"), user.Team, user.Status, shared.BoolText(user.MFAEnabled), lastLogin, }) } writer.Flush() if err := writer.Error(); err != nil { return UserExport{}, err } return UserExport{FileName: "hyapp-users.csv", Content: buf.Bytes(), Count: len(users)}, nil } func roleNames(roles []model.Role) []string { names := make([]string, 0, len(roles)) for _, role := range roles { names = append(names, role.Name) } return names }