// Admin 用户管理业务:列表、新增采购员、启停和重置密码。 package service import ( "database/sql" "errors" "strings" "time" "cmautobuy/admin/model" "cmautobuy/admin/repository" ) var ErrAdminRequired = errors.New("只有管理员可以执行此管理操作") // UserListResult 是用户管理页的分页结果。 type UserListResult struct { Rows []model.User Keyword string Status model.UserStatus Page int Total int TotalPages int } // ListUsers 搜索并分页。用户页沿用全站统一的每页 20 条规则。 func ListUsers(db *sql.DB, actor *model.User, keyword string, status model.UserStatus, requestedPage int) (*UserListResult, error) { if actor == nil || !actor.IsAdmin() { return nil, ErrAdminRequired } keyword = strings.TrimSpace(keyword) if status != model.UserActive && status != model.UserDisabled { status = "" } page := requestedPage if page < 1 { page = 1 } rows, total, err := repository.ListUsers(db, keyword, status, PageSize, (page-1)*PageSize) if err != nil { return nil, err } totalPages := TotalPages(total) clampedPage := ClampPage(page, totalPages) if clampedPage != page { page = clampedPage rows, _, err = repository.ListUsers(db, keyword, status, PageSize, (page-1)*PageSize) if err != nil { return nil, err } } return &UserListResult{ Rows: rows, Keyword: keyword, Status: status, Page: page, Total: total, TotalPages: totalPages, }, nil } // CreatePurchaser 创建固定 purchaser 角色的账号,不提供第二管理员入口。 func CreatePurchaser(db *sql.DB, actor *model.User, username, password, confirmation string, now time.Time) error { if actor == nil || !actor.IsAdmin() { return ErrAdminRequired } username = strings.TrimSpace(username) if err := validateUsername(username); err != nil { return err } hash, err := hashConfirmedPassword(password, confirmation) if err != nil { return err } userID, err := randomID("USR-", 16) if err != nil { return err } at := now.UTC().Format(model.TimeLayout) return repository.CreateUser(db, model.User{ UserID: userID, Username: username, PasswordHash: string(hash), Role: model.RolePurchaser, Status: model.UserActive, PasswordChangedAt: at, CreatedAt: at, UpdatedAt: at, }) } // ChangeUserStatus 启用或禁用账号。数据库事务负责最后管理员保护和 Session 撤销。 func ChangeUserStatus(db *sql.DB, actor *model.User, userID string, status model.UserStatus, now time.Time) error { if actor == nil || !actor.IsAdmin() { return ErrAdminRequired } if status != model.UserActive && status != model.UserDisabled { return invalidInput("账号状态无效") } if strings.TrimSpace(userID) == "" { return invalidInput("用户编号不能为空") } return repository.SetUserStatusAndRevokeSessions( db, userID, status, now.UTC().Format(model.TimeLayout)) } // ResetUserPassword 更新密码哈希,并在同一事务中撤销目标用户全部 Session。 func ResetUserPassword(db *sql.DB, actor *model.User, userID, password, confirmation string, now time.Time) error { if actor == nil || !actor.IsAdmin() { return ErrAdminRequired } if strings.TrimSpace(userID) == "" { return invalidInput("用户编号不能为空") } hash, err := hashConfirmedPassword(password, confirmation) if err != nil { return err } return repository.ResetUserPasswordAndRevokeSessions( db, userID, string(hash), now.UTC().Format(model.TimeLayout)) }