wz-golang-server/server/modules/user/service/user_service.go

250 lines
6.0 KiB
Go

// Package service 业务逻辑层
package service
import (
"context"
"encoding/json"
"errors"
"strconv"
"strings"
"time"
"server/common"
"server/config"
systemEntity "server/modules/system/entity"
"server/modules/user/dto"
"server/modules/user/entity"
"server/modules/user/mapper"
"server/modules/user/vo"
"github.com/google/uuid"
"gorm.io/datatypes"
"gorm.io/gorm"
)
type UserService struct {
mapper *mapper.UserMapper
platformUserMapper *mapper.PlatformUserMapper
}
func NewUserService() *UserService {
return &UserService{
mapper: mapper.NewUserMapper(),
platformUserMapper: mapper.NewPlatformUserMapper(),
}
}
// List 获取用户列表
func (s *UserService) List(page, size int) ([]entity.User, int64, error) {
return s.mapper.FindAll(page, size)
}
// GetByID 获取用户详情
func (s *UserService) GetByID(id int64) (*entity.User, error) {
return s.mapper.FindByID(id)
}
// Create 创建用户
func (s *UserService) Create(req *dto.CreateUserRequest) (*entity.User, error) {
phone := normalizeOptionalString(req.Phone)
user := &entity.User{
Username: req.Username,
Nickname: req.Nickname,
AvatarURL: req.AvatarURL,
Phone: phone,
Gender: 0,
Status: 1,
DelFlag: 0,
}
if req.Gender != nil {
user.Gender = *req.Gender
}
if req.Status != nil {
user.Status = *req.Status
}
if err := s.mapper.Create(user); err != nil {
return nil, err
}
return user, nil
}
// Update 更新用户
func (s *UserService) Update(id int64, req *dto.UpdateUserRequest) (*entity.User, error) {
fields := make(map[string]interface{})
if req.Username != nil {
fields["username"] = *req.Username
}
if req.Nickname != nil {
fields["nickname"] = *req.Nickname
}
if req.AvatarURL != nil {
fields["avatar_url"] = *req.AvatarURL
}
if req.Phone != nil {
fields["phone"] = normalizeOptionalString(req.Phone)
}
if req.Gender != nil {
fields["gender"] = *req.Gender
}
if req.Status != nil {
fields["status"] = *req.Status
}
if len(fields) == 0 {
return s.mapper.FindByID(id)
}
fields["update_time"] = time.Now()
if err := s.mapper.UpdateFields(id, fields); err != nil {
return nil, err
}
return s.mapper.FindByID(id)
}
// UpdateFields 动态字段更新
func (s *UserService) UpdateFields(id int64, fields map[string]interface{}) error {
if len(fields) == 0 {
return nil
}
fields["update_time"] = time.Now()
return s.mapper.UpdateFields(id, fields)
}
// Delete 删除用户
func (s *UserService) Delete(id int64) error {
return s.mapper.Delete(id)
}
func normalizeOptionalString(val *string) *string {
if val == nil {
return nil
}
trimmed := strings.TrimSpace(*val)
if trimmed == "" {
return nil
}
return &trimmed
}
// LoginByPhonePassword 手机号密码登录
func (s *UserService) LoginByPhonePassword(phone, password string) (*systemEntity.LoginUser, string, error) {
phone = strings.TrimSpace(phone)
if phone == "" || strings.TrimSpace(password) == "" {
return nil, "", errors.New("手机号或密码不能为空")
}
user, err := s.mapper.FindByPhone(phone)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, "", errors.New("用户不存在")
}
return nil, "", err
}
if user.Status == 0 {
return nil, "", errors.New("账号已被禁用")
}
if user.Password == nil || strings.TrimSpace(*user.Password) == "" || user.Salt == nil || strings.TrimSpace(*user.Salt) == "" {
return nil, "", errors.New("用户未设置密码")
}
encrypted, err := common.Encrypt(phone, password, *user.Salt)
if err != nil {
return nil, "", errors.New("密码校验失败")
}
if encrypted != *user.Password {
return nil, "", errors.New("手机号或密码错误")
}
token := uuid.NewString()
loginUser := &systemEntity.LoginUser{
ID: strconv.FormatInt(user.ID, 10),
Username: chooseUsernameForLogin(user.Username, phone),
Realname: user.Nickname,
Avatar: user.AvatarURL,
Phone: phone,
Email: "",
Token: token,
}
if err := s.saveLoginUser(token, loginUser); err != nil {
return nil, "", errors.New("登录失败,请重试")
}
return loginUser, token, nil
}
func chooseUsernameForLogin(username, phone string) string {
if strings.TrimSpace(username) != "" {
return username
}
return phone
}
func (s *UserService) saveLoginUser(token string, user *systemEntity.LoginUser) error {
ctx := context.Background()
data, err := json.Marshal(user)
if err != nil {
return err
}
return config.RDB.Set(ctx, common.RedisTokenPrefix+token, data, common.RedisTokenExpire).Err()
}
// GetProfile 获取登录用户信息
func (s *UserService) GetProfile(userID int64, platformType int8) (*vo.UserProfileVO, error) {
user, err := s.mapper.FindByID(userID)
if err != nil {
return nil, err
}
var platform *entity.PlatformUser
platform, err = s.platformUserMapper.FindByUserIDAndPlatformType(userID, platformType)
if err != nil {
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, err
}
platform = nil
}
profile := &vo.UserProfileVO{
UserID: user.ID,
Username: user.Username,
Nickname: user.Nickname,
AvatarURL: user.AvatarURL,
Phone: normalizeValue(user.Phone),
Gender: user.Gender,
}
if platform != nil {
profile.PlatformType = platform.PlatformType
profile.PlatformOpenID = platform.PlatformOpenID
profile.PlatformUnionID = platform.PlatformUnionID
profile.PlatformExtra = platform.PlatformExtra
profile.Region = buildRegion(platform.PlatformExtra)
}
return profile, nil
}
func normalizeValue(val *string) string {
if val == nil {
return ""
}
return strings.TrimSpace(*val)
}
func buildRegion(extra datatypes.JSONMap) string {
if extra == nil {
return ""
}
if region, ok := extra["region"].(string); ok && strings.TrimSpace(region) != "" {
return strings.TrimSpace(region)
}
province, _ := extra["province"].(string)
city, _ := extra["city"].(string)
country, _ := extra["country"].(string)
parts := []string{}
for _, item := range []string{country, province, city} {
if strings.TrimSpace(item) != "" {
parts = append(parts, strings.TrimSpace(item))
}
}
return strings.Join(parts, " ")
}