f
This commit is contained in:
77
internal/application/user/dto/commands/user_commands.go
Normal file
77
internal/application/user/dto/commands/user_commands.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package commands
|
||||
|
||||
// RegisterUserCommand 用户注册命令
|
||||
// @Description 用户注册请求参数
|
||||
type RegisterUserCommand struct {
|
||||
Phone string `json:"phone" binding:"required,phone" example:"13800138000"`
|
||||
Password string `json:"password" binding:"required,strong_password" example:"Password123"`
|
||||
ConfirmPassword string `json:"confirm_password" binding:"required,eqfield=Password" example:"Password123"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// LoginWithPasswordCommand 密码登录命令
|
||||
// @Description 使用密码进行用户登录请求参数
|
||||
type LoginWithPasswordCommand struct {
|
||||
Phone string `json:"phone" binding:"required,phone" example:"13800138000"`
|
||||
Password string `json:"password" binding:"required,min=6,max=128" example:"Password123"`
|
||||
}
|
||||
|
||||
// LoginWithSMSCommand 短信验证码登录命令
|
||||
// @Description 使用短信验证码进行用户登录请求参数
|
||||
type LoginWithSMSCommand struct {
|
||||
Phone string `json:"phone" binding:"required,phone" example:"13800138000"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// ChangePasswordCommand 修改密码命令
|
||||
// @Description 修改用户密码请求参数
|
||||
type ChangePasswordCommand struct {
|
||||
UserID string `json:"-"`
|
||||
OldPassword string `json:"old_password" binding:"required,min=6,max=128" example:"OldPassword123"`
|
||||
NewPassword string `json:"new_password" binding:"required,strong_password" example:"NewPassword123"`
|
||||
ConfirmNewPassword string `json:"confirm_new_password" binding:"required,eqfield=NewPassword" example:"NewPassword123"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// ResetPasswordCommand 重置密码命令
|
||||
// @Description 重置用户密码请求参数(忘记密码时使用)
|
||||
type ResetPasswordCommand struct {
|
||||
Phone string `json:"phone" binding:"required,phone" example:"13800138000"`
|
||||
NewPassword string `json:"new_password" binding:"required,strong_password" example:"NewPassword123"`
|
||||
ConfirmNewPassword string `json:"confirm_new_password" binding:"required,eqfield=NewPassword" example:"NewPassword123"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
}
|
||||
|
||||
// SendCodeCommand 发送验证码命令
|
||||
// @Description 发送短信验证码请求参数。只接收编码后的data字段(使用自定义编码方案,非Base64)
|
||||
type SendCodeCommand struct {
|
||||
// 编码后的数据(使用自定义编码方案的JSON字符串,包含所有参数:phone, scene, timestamp, nonce, signature)
|
||||
Data string `json:"data" binding:"required" example:"K8mN9vP2sL7kH3oB6yC1zA5uF0qE9tW..."` // 自定义编码后的数据
|
||||
|
||||
// 阿里云滑块验证码参数(直接接收,不参与编码)
|
||||
CaptchaVerifyParam string `json:"captchaVerifyParam,omitempty" example:"..."` // 滑块验证码验证参数
|
||||
|
||||
// 以下字段从data解码后填充,不直接接收
|
||||
Phone string `json:"-"` // 从data解码后获取
|
||||
Scene string `json:"-"` // 从data解码后获取
|
||||
Timestamp int64 `json:"-"` // 从data解码后获取
|
||||
Nonce string `json:"-"` // 从data解码后获取
|
||||
Signature string `json:"-"` // 从data解码后获取
|
||||
}
|
||||
|
||||
// UpdateProfileCommand 更新用户信息命令
|
||||
// @Description 更新用户基本信息请求参数
|
||||
type UpdateProfileCommand struct {
|
||||
UserID string `json:"-"`
|
||||
Phone string `json:"phone" binding:"omitempty,phone" example:"13800138000"`
|
||||
DisplayName string `json:"display_name" binding:"omitempty,min=2,max=50" example:"用户昵称"`
|
||||
Email string `json:"email" binding:"omitempty,email" example:"user@example.com"`
|
||||
}
|
||||
|
||||
// VerifyCodeCommand 验证验证码命令
|
||||
// @Description 验证短信验证码请求参数
|
||||
type VerifyCodeCommand struct {
|
||||
Phone string `json:"phone" binding:"required,phone" example:"13800138000"`
|
||||
Code string `json:"code" binding:"required,len=6" example:"123456"`
|
||||
Scene string `json:"scene" binding:"required,oneof=register login change_password reset_password bind unbind certification" example:"register"`
|
||||
}
|
||||
6
internal/application/user/dto/queries/get_user_query.go
Normal file
6
internal/application/user/dto/queries/get_user_query.go
Normal file
@@ -0,0 +1,6 @@
|
||||
package queries
|
||||
|
||||
// GetUserQuery 获取用户信息查询
|
||||
type GetUserQuery struct {
|
||||
UserID string `json:"user_id"`
|
||||
}
|
||||
31
internal/application/user/dto/queries/list_users_query.go
Normal file
31
internal/application/user/dto/queries/list_users_query.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package queries
|
||||
|
||||
import "hyapi-server/internal/domains/user/repositories/queries"
|
||||
|
||||
// ListUsersQuery 用户列表查询DTO
|
||||
type ListUsersQuery struct {
|
||||
Page int `json:"page" validate:"min=1"`
|
||||
PageSize int `json:"page_size" validate:"min=1,max=100"`
|
||||
Phone string `json:"phone"`
|
||||
UserType string `json:"user_type"` // 用户类型: user/admin
|
||||
IsActive *bool `json:"is_active"` // 是否激活
|
||||
IsCertified *bool `json:"is_certified"` // 是否已认证
|
||||
CompanyName string `json:"company_name"` // 企业名称
|
||||
StartDate string `json:"start_date"`
|
||||
EndDate string `json:"end_date"`
|
||||
}
|
||||
|
||||
// ToDomainQuery 转换为领域查询对象
|
||||
func (q *ListUsersQuery) ToDomainQuery() *queries.ListUsersQuery {
|
||||
return &queries.ListUsersQuery{
|
||||
Page: q.Page,
|
||||
PageSize: q.PageSize,
|
||||
Phone: q.Phone,
|
||||
UserType: q.UserType,
|
||||
IsActive: q.IsActive,
|
||||
IsCertified: q.IsCertified,
|
||||
CompanyName: q.CompanyName,
|
||||
StartDate: q.StartDate,
|
||||
EndDate: q.EndDate,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package responses
|
||||
|
||||
import "time"
|
||||
|
||||
// UserListItem 用户列表项
|
||||
type UserListItem struct {
|
||||
ID string `json:"id"`
|
||||
Phone string `json:"phone"`
|
||||
UserType string `json:"user_type"`
|
||||
Username string `json:"username"`
|
||||
IsActive bool `json:"is_active"`
|
||||
IsCertified bool `json:"is_certified"`
|
||||
LoginCount int `json:"login_count"`
|
||||
LastLoginAt *time.Time `json:"last_login_at"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// 企业信息
|
||||
EnterpriseInfo *EnterpriseInfoItem `json:"enterprise_info,omitempty"`
|
||||
|
||||
// 钱包信息
|
||||
WalletBalance string `json:"wallet_balance,omitempty"`
|
||||
}
|
||||
|
||||
// EnterpriseInfoItem 企业信息项
|
||||
type EnterpriseInfoItem struct {
|
||||
ID string `json:"id"`
|
||||
CompanyName string `json:"company_name"`
|
||||
UnifiedSocialCode string `json:"unified_social_code"`
|
||||
LegalPersonName string `json:"legal_person_name"`
|
||||
LegalPersonPhone string `json:"legal_person_phone"`
|
||||
EnterpriseAddress string `json:"enterprise_address"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// 合同信息
|
||||
Contracts []*ContractInfoItem `json:"contracts,omitempty"`
|
||||
}
|
||||
|
||||
// ContractInfoItem 合同信息项
|
||||
type ContractInfoItem struct {
|
||||
ID string `json:"id"`
|
||||
ContractName string `json:"contract_name"`
|
||||
ContractType string `json:"contract_type"` // 合同类型代码
|
||||
ContractTypeName string `json:"contract_type_name"` // 合同类型中文名称
|
||||
ContractFileURL string `json:"contract_file_url"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// UserListResponse 用户列表响应
|
||||
type UserListResponse struct {
|
||||
Items []*UserListItem `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
Page int `json:"page"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
// UserStatsResponse 用户统计响应
|
||||
type UserStatsResponse struct {
|
||||
TotalUsers int64 `json:"total_users"`
|
||||
ActiveUsers int64 `json:"active_users"`
|
||||
CertifiedUsers int64 `json:"certified_users"`
|
||||
}
|
||||
|
||||
// UserDetailResponse 用户详情响应
|
||||
type UserDetailResponse struct {
|
||||
*UserListItem
|
||||
}
|
||||
69
internal/application/user/dto/responses/user_responses.go
Normal file
69
internal/application/user/dto/responses/user_responses.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package responses
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// RegisterUserResponse 用户注册响应
|
||||
// @Description 用户注册成功响应
|
||||
type RegisterUserResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Phone string `json:"phone" example:"13800138000"`
|
||||
}
|
||||
|
||||
// EnterpriseInfoResponse 企业信息响应
|
||||
// @Description 企业信息响应
|
||||
type EnterpriseInfoResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
CompanyName string `json:"company_name" example:"示例企业有限公司"`
|
||||
UnifiedSocialCode string `json:"unified_social_code" example:"91110000123456789X"`
|
||||
LegalPersonName string `json:"legal_person_name" example:"张三"`
|
||||
LegalPersonID string `json:"legal_person_id" example:"110101199001011234"`
|
||||
LegalPersonPhone string `json:"legal_person_phone" example:"13800138000"`
|
||||
EnterpriseAddress string `json:"enterprise_address" example:"北京市朝阳区xxx街道xxx号"`
|
||||
CertifiedAt *time.Time `json:"certified_at,omitempty" example:"2024-01-01T00:00:00Z"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"`
|
||||
}
|
||||
|
||||
// LoginUserResponse 用户登录响应
|
||||
// @Description 用户登录成功响应
|
||||
type LoginUserResponse struct {
|
||||
User *UserProfileResponse `json:"user"`
|
||||
AccessToken string `json:"access_token" example:"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."`
|
||||
TokenType string `json:"token_type" example:"Bearer"`
|
||||
ExpiresIn int64 `json:"expires_in" example:"86400"`
|
||||
LoginMethod string `json:"login_method" example:"password"`
|
||||
}
|
||||
|
||||
// UserProfileResponse 用户信息响应
|
||||
// @Description 用户基本信息
|
||||
type UserProfileResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Phone string `json:"phone" example:"13800138000"`
|
||||
Username string `json:"username,omitempty" example:"admin"`
|
||||
UserType string `json:"user_type" example:"user"`
|
||||
IsActive bool `json:"is_active" example:"true"`
|
||||
LastLoginAt *time.Time `json:"last_login_at,omitempty" example:"2024-01-01T00:00:00Z"`
|
||||
LoginCount int `json:"login_count" example:"10"`
|
||||
Permissions []string `json:"permissions,omitempty" example:"['user:read','user:write']"`
|
||||
EnterpriseInfo *EnterpriseInfoResponse `json:"enterprise_info,omitempty"`
|
||||
IsCertified bool `json:"is_certified" example:"false"`
|
||||
CreatedAt time.Time `json:"created_at" example:"2024-01-01T00:00:00Z"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"`
|
||||
}
|
||||
|
||||
// SendCodeResponse 发送验证码响应
|
||||
// @Description 发送短信验证码成功响应
|
||||
type SendCodeResponse struct {
|
||||
Message string `json:"message" example:"验证码发送成功"`
|
||||
ExpiresAt time.Time `json:"expires_at" example:"2024-01-01T00:05:00Z"`
|
||||
}
|
||||
|
||||
// UpdateProfileResponse 更新用户信息响应
|
||||
// @Description 更新用户信息成功响应
|
||||
type UpdateProfileResponse struct {
|
||||
ID string `json:"id" example:"123e4567-e89b-12d3-a456-426614174000"`
|
||||
Phone string `json:"phone" example:"13800138000"`
|
||||
UpdatedAt time.Time `json:"updated_at" example:"2024-01-01T00:00:00Z"`
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"hyapi-server/internal/application/user/dto/commands"
|
||||
"hyapi-server/internal/domains/user/entities"
|
||||
)
|
||||
|
||||
func (s *UserApplicationServiceImpl) SendCode(ctx context.Context, cmd *commands.SendCodeCommand, clientIP, userAgent string) error {
|
||||
// 1. 检查频率限制
|
||||
if err := s.smsCodeService.CheckRateLimit(ctx, cmd.Phone, entities.SMSScene(cmd.Scene), clientIP, userAgent); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err := s.smsCodeService.SendCode(ctx, cmd.Phone, entities.SMSScene(cmd.Scene), clientIP, userAgent, cmd.CaptchaVerifyParam)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
25
internal/application/user/user_application_service.go
Normal file
25
internal/application/user/user_application_service.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"hyapi-server/internal/application/user/dto/commands"
|
||||
"hyapi-server/internal/application/user/dto/queries"
|
||||
"hyapi-server/internal/application/user/dto/responses"
|
||||
)
|
||||
|
||||
// UserApplicationService 用户应用服务接口
|
||||
type UserApplicationService interface {
|
||||
Register(ctx context.Context, cmd *commands.RegisterUserCommand) (*responses.RegisterUserResponse, error)
|
||||
LoginWithPassword(ctx context.Context, cmd *commands.LoginWithPasswordCommand) (*responses.LoginUserResponse, error)
|
||||
LoginWithSMS(ctx context.Context, cmd *commands.LoginWithSMSCommand) (*responses.LoginUserResponse, error)
|
||||
ChangePassword(ctx context.Context, cmd *commands.ChangePasswordCommand) error
|
||||
ResetPassword(ctx context.Context, cmd *commands.ResetPasswordCommand) error
|
||||
GetUserProfile(ctx context.Context, userID string) (*responses.UserProfileResponse, error)
|
||||
SendCode(ctx context.Context, cmd *commands.SendCodeCommand, clientIP, userAgent string) error
|
||||
|
||||
// 管理员功能
|
||||
ListUsers(ctx context.Context, query *queries.ListUsersQuery) (*responses.UserListResponse, error)
|
||||
GetUserDetail(ctx context.Context, userID string) (*responses.UserDetailResponse, error)
|
||||
GetUserStats(ctx context.Context) (*responses.UserStatsResponse, error)
|
||||
}
|
||||
461
internal/application/user/user_application_service_impl.go
Normal file
461
internal/application/user/user_application_service_impl.go
Normal file
@@ -0,0 +1,461 @@
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"hyapi-server/internal/application/user/dto/commands"
|
||||
"hyapi-server/internal/application/user/dto/queries"
|
||||
"hyapi-server/internal/application/user/dto/responses"
|
||||
finance_service "hyapi-server/internal/domains/finance/services"
|
||||
"hyapi-server/internal/domains/user/entities"
|
||||
"hyapi-server/internal/domains/user/events"
|
||||
user_service "hyapi-server/internal/domains/user/services"
|
||||
"hyapi-server/internal/shared/interfaces"
|
||||
"hyapi-server/internal/shared/middleware"
|
||||
)
|
||||
|
||||
// UserApplicationServiceImpl 用户应用服务实现
|
||||
// 负责业务流程编排、事务管理、数据转换,不直接操作仓库
|
||||
type UserApplicationServiceImpl struct {
|
||||
userAggregateService user_service.UserAggregateService
|
||||
userAuthService *user_service.UserAuthService
|
||||
smsCodeService *user_service.SMSCodeService
|
||||
walletService finance_service.WalletAggregateService
|
||||
contractService user_service.ContractAggregateService
|
||||
eventBus interfaces.EventBus
|
||||
jwtAuth *middleware.JWTAuthMiddleware
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewUserApplicationService 创建用户应用服务
|
||||
func NewUserApplicationService(
|
||||
userAggregateService user_service.UserAggregateService,
|
||||
userAuthService *user_service.UserAuthService,
|
||||
smsCodeService *user_service.SMSCodeService,
|
||||
walletService finance_service.WalletAggregateService,
|
||||
contractService user_service.ContractAggregateService,
|
||||
eventBus interfaces.EventBus,
|
||||
jwtAuth *middleware.JWTAuthMiddleware,
|
||||
logger *zap.Logger,
|
||||
) UserApplicationService {
|
||||
return &UserApplicationServiceImpl{
|
||||
userAggregateService: userAggregateService,
|
||||
userAuthService: userAuthService,
|
||||
smsCodeService: smsCodeService,
|
||||
walletService: walletService,
|
||||
contractService: contractService,
|
||||
eventBus: eventBus,
|
||||
jwtAuth: jwtAuth,
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
// 业务流程:1. 验证短信验证码 2. 创建用户 3. 发布注册事件
|
||||
func (s *UserApplicationServiceImpl) Register(ctx context.Context, cmd *commands.RegisterUserCommand) (*responses.RegisterUserResponse, error) {
|
||||
// 1. 验证短信验证码
|
||||
if err := s.smsCodeService.VerifyCode(ctx, cmd.Phone, cmd.Code, entities.SMSSceneRegister); err != nil {
|
||||
return nil, fmt.Errorf("验证码错误或已过期")
|
||||
}
|
||||
|
||||
// 2. 创建用户
|
||||
user, err := s.userAggregateService.CreateUser(ctx, cmd.Phone, cmd.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. 发布用户注册事件
|
||||
event := events.NewUserRegisteredEvent(user, "")
|
||||
if err := s.eventBus.Publish(ctx, event); err != nil {
|
||||
s.logger.Warn("发布用户注册事件失败", zap.Error(err))
|
||||
}
|
||||
|
||||
s.logger.Info("用户注册成功", zap.String("user_id", user.ID), zap.String("phone", user.Phone))
|
||||
|
||||
return &responses.RegisterUserResponse{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoginWithPassword 密码登录
|
||||
// 业务流程:1. 验证用户密码 2. 生成访问令牌 3. 更新登录统计 4. 获取用户权限
|
||||
func (s *UserApplicationServiceImpl) LoginWithPassword(ctx context.Context, cmd *commands.LoginWithPasswordCommand) (*responses.LoginUserResponse, error) {
|
||||
// 1. 验证用户密码
|
||||
user, err := s.userAuthService.ValidatePassword(ctx, cmd.Phone, cmd.Password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 生成包含用户类型的token
|
||||
accessToken, err := s.jwtAuth.GenerateToken(user.ID, user.Phone, user.Phone, user.UserType)
|
||||
if err != nil {
|
||||
s.logger.Error("生成令牌失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("生成访问令牌失败")
|
||||
}
|
||||
|
||||
// 3. 如果是管理员,更新登录统计
|
||||
if user.IsAdmin() {
|
||||
if err := s.userAggregateService.UpdateLoginStats(ctx, user.ID); err != nil {
|
||||
s.logger.Error("更新登录统计失败", zap.Error(err))
|
||||
}
|
||||
// 重新获取用户信息以获取最新的登录统计
|
||||
updatedUser, err := s.userAggregateService.GetUserByID(ctx, user.ID)
|
||||
if err != nil {
|
||||
s.logger.Error("重新获取用户信息失败", zap.Error(err))
|
||||
} else {
|
||||
user = updatedUser
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 获取用户权限(仅管理员)
|
||||
var permissions []string
|
||||
if user.IsAdmin() {
|
||||
permissions, err = s.userAuthService.GetUserPermissions(ctx, user)
|
||||
if err != nil {
|
||||
s.logger.Error("获取用户权限失败", zap.Error(err))
|
||||
permissions = []string{}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 构建用户信息
|
||||
userProfile := &responses.UserProfileResponse{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
Username: user.Username,
|
||||
UserType: user.UserType,
|
||||
IsActive: user.Active,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
LoginCount: user.LoginCount,
|
||||
Permissions: permissions,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
|
||||
return &responses.LoginUserResponse{
|
||||
User: userProfile,
|
||||
AccessToken: accessToken,
|
||||
TokenType: "Bearer",
|
||||
ExpiresIn: 86400, // 24h
|
||||
LoginMethod: "password",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoginWithSMS 短信验证码登录
|
||||
// 业务流程:1. 验证短信验证码 2. 验证用户登录状态 3. 生成访问令牌 4. 更新登录统计 5. 获取用户权限
|
||||
func (s *UserApplicationServiceImpl) LoginWithSMS(ctx context.Context, cmd *commands.LoginWithSMSCommand) (*responses.LoginUserResponse, error) {
|
||||
// 1. 验证短信验证码
|
||||
if err := s.smsCodeService.VerifyCode(ctx, cmd.Phone, cmd.Code, entities.SMSSceneLogin); err != nil {
|
||||
return nil, fmt.Errorf("验证码错误或已过期")
|
||||
}
|
||||
|
||||
// 2. 验证用户登录状态
|
||||
user, err := s.userAuthService.ValidateUserLogin(ctx, cmd.Phone)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 3. 生成包含用户类型的token
|
||||
accessToken, err := s.jwtAuth.GenerateToken(user.ID, user.Phone, user.Phone, user.UserType)
|
||||
if err != nil {
|
||||
s.logger.Error("生成令牌失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("生成访问令牌失败")
|
||||
}
|
||||
|
||||
// 4. 如果是管理员,更新登录统计
|
||||
if user.IsAdmin() {
|
||||
if err := s.userAggregateService.UpdateLoginStats(ctx, user.ID); err != nil {
|
||||
s.logger.Error("更新登录统计失败", zap.Error(err))
|
||||
}
|
||||
// 重新获取用户信息以获取最新的登录统计
|
||||
updatedUser, err := s.userAggregateService.GetUserByID(ctx, user.ID)
|
||||
if err != nil {
|
||||
s.logger.Error("重新获取用户信息失败", zap.Error(err))
|
||||
} else {
|
||||
user = updatedUser
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 获取用户权限(仅管理员)
|
||||
var permissions []string
|
||||
if user.IsAdmin() {
|
||||
permissions, err = s.userAuthService.GetUserPermissions(ctx, user)
|
||||
if err != nil {
|
||||
s.logger.Error("获取用户权限失败", zap.Error(err))
|
||||
permissions = []string{}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 构建用户信息
|
||||
userProfile := &responses.UserProfileResponse{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
Username: user.Username,
|
||||
UserType: user.UserType,
|
||||
IsActive: user.Active,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
LoginCount: user.LoginCount,
|
||||
Permissions: permissions,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
|
||||
return &responses.LoginUserResponse{
|
||||
User: userProfile,
|
||||
AccessToken: accessToken,
|
||||
TokenType: "Bearer",
|
||||
ExpiresIn: int64(s.jwtAuth.GetExpiresIn().Seconds()), // 168h
|
||||
LoginMethod: "sms",
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ChangePassword 修改密码
|
||||
// 业务流程:1. 修改用户密码
|
||||
func (s *UserApplicationServiceImpl) ChangePassword(ctx context.Context, cmd *commands.ChangePasswordCommand) error {
|
||||
return s.userAuthService.ChangePassword(ctx, cmd.UserID, cmd.OldPassword, cmd.NewPassword)
|
||||
}
|
||||
|
||||
// ResetPassword 重置密码
|
||||
// 业务流程:1. 验证短信验证码 2. 重置用户密码
|
||||
func (s *UserApplicationServiceImpl) ResetPassword(ctx context.Context, cmd *commands.ResetPasswordCommand) error {
|
||||
// 1. 验证短信验证码
|
||||
if err := s.smsCodeService.VerifyCode(ctx, cmd.Phone, cmd.Code, entities.SMSSceneResetPassword); err != nil {
|
||||
return fmt.Errorf("验证码错误或已过期")
|
||||
}
|
||||
|
||||
// 2. 重置用户密码
|
||||
return s.userAuthService.ResetPassword(ctx, cmd.Phone, cmd.NewPassword)
|
||||
}
|
||||
|
||||
// GetUserProfile 获取用户资料
|
||||
// 业务流程:1. 获取用户信息 2. 获取企业信息 3. 构建响应数据
|
||||
func (s *UserApplicationServiceImpl) GetUserProfile(ctx context.Context, userID string) (*responses.UserProfileResponse, error) {
|
||||
// 1. 获取用户信息(包含企业信息)
|
||||
user, err := s.userAggregateService.GetUserWithEnterpriseInfo(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 获取用户权限(仅管理员)
|
||||
var permissions []string
|
||||
if user.IsAdmin() {
|
||||
permissions, err = s.userAuthService.GetUserPermissions(ctx, user)
|
||||
if err != nil {
|
||||
s.logger.Error("获取用户权限失败", zap.Error(err))
|
||||
permissions = []string{}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 构建用户信息
|
||||
userProfile := &responses.UserProfileResponse{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
Username: user.Username,
|
||||
UserType: user.UserType,
|
||||
IsActive: user.Active,
|
||||
IsCertified: user.IsCertified,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
LoginCount: user.LoginCount,
|
||||
Permissions: permissions,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
|
||||
// 4. 添加企业信息
|
||||
if user.EnterpriseInfo != nil {
|
||||
userProfile.EnterpriseInfo = &responses.EnterpriseInfoResponse{
|
||||
ID: user.EnterpriseInfo.ID,
|
||||
CompanyName: user.EnterpriseInfo.CompanyName,
|
||||
UnifiedSocialCode: user.EnterpriseInfo.UnifiedSocialCode,
|
||||
LegalPersonName: user.EnterpriseInfo.LegalPersonName,
|
||||
LegalPersonID: user.EnterpriseInfo.LegalPersonID,
|
||||
LegalPersonPhone: user.EnterpriseInfo.LegalPersonPhone,
|
||||
EnterpriseAddress: user.EnterpriseInfo.EnterpriseAddress,
|
||||
CreatedAt: user.EnterpriseInfo.CreatedAt,
|
||||
UpdatedAt: user.EnterpriseInfo.UpdatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
return userProfile, nil
|
||||
}
|
||||
|
||||
// GetUser 获取用户信息
|
||||
// 业务流程:1. 获取用户信息 2. 构建响应数据
|
||||
func (s *UserApplicationServiceImpl) GetUser(ctx context.Context, query *queries.GetUserQuery) (*responses.UserProfileResponse, error) {
|
||||
user, err := s.userAggregateService.GetUserByID(ctx, query.UserID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &responses.UserProfileResponse{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
Username: user.Username,
|
||||
UserType: user.UserType,
|
||||
IsActive: user.Active,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
LoginCount: user.LoginCount,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListUsers 获取用户列表(管理员功能)
|
||||
// 业务流程:1. 查询用户列表 2. 构建响应数据
|
||||
func (s *UserApplicationServiceImpl) ListUsers(ctx context.Context, query *queries.ListUsersQuery) (*responses.UserListResponse, error) {
|
||||
// 1. 查询用户列表
|
||||
users, total, err := s.userAggregateService.ListUsers(ctx, query.ToDomainQuery())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 构建响应数据
|
||||
items := make([]*responses.UserListItem, 0, len(users))
|
||||
for _, user := range users {
|
||||
item := &responses.UserListItem{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
UserType: user.UserType,
|
||||
Username: user.Username,
|
||||
IsActive: user.Active,
|
||||
IsCertified: user.IsCertified,
|
||||
LoginCount: user.LoginCount,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
|
||||
// 添加企业信息
|
||||
if user.EnterpriseInfo != nil {
|
||||
item.EnterpriseInfo = &responses.EnterpriseInfoItem{
|
||||
ID: user.EnterpriseInfo.ID,
|
||||
CompanyName: user.EnterpriseInfo.CompanyName,
|
||||
UnifiedSocialCode: user.EnterpriseInfo.UnifiedSocialCode,
|
||||
LegalPersonName: user.EnterpriseInfo.LegalPersonName,
|
||||
LegalPersonPhone: user.EnterpriseInfo.LegalPersonPhone,
|
||||
EnterpriseAddress: user.EnterpriseInfo.EnterpriseAddress,
|
||||
CreatedAt: user.EnterpriseInfo.CreatedAt,
|
||||
}
|
||||
|
||||
// 获取企业合同信息
|
||||
contracts, err := s.contractService.FindByUserID(ctx, user.ID)
|
||||
if err == nil && len(contracts) > 0 {
|
||||
contractItems := make([]*responses.ContractInfoItem, 0, len(contracts))
|
||||
for _, contract := range contracts {
|
||||
contractItems = append(contractItems, &responses.ContractInfoItem{
|
||||
ID: contract.ID,
|
||||
ContractName: contract.ContractName,
|
||||
ContractType: string(contract.ContractType),
|
||||
ContractTypeName: contract.GetContractTypeName(),
|
||||
ContractFileURL: contract.ContractFileURL,
|
||||
CreatedAt: contract.CreatedAt,
|
||||
})
|
||||
}
|
||||
item.EnterpriseInfo.Contracts = contractItems
|
||||
}
|
||||
}
|
||||
|
||||
// 添加钱包余额信息
|
||||
wallet, err := s.walletService.LoadWalletByUserId(ctx, user.ID)
|
||||
if err == nil && wallet != nil {
|
||||
item.WalletBalance = wallet.Balance.String()
|
||||
} else {
|
||||
item.WalletBalance = "0"
|
||||
}
|
||||
|
||||
items = append(items, item)
|
||||
}
|
||||
|
||||
return &responses.UserListResponse{
|
||||
Items: items,
|
||||
Total: total,
|
||||
Page: query.Page,
|
||||
Size: query.PageSize,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUserDetail 获取用户详情(管理员功能)
|
||||
// 业务流程:1. 查询用户详情 2. 构建响应数据
|
||||
func (s *UserApplicationServiceImpl) GetUserDetail(ctx context.Context, userID string) (*responses.UserDetailResponse, error) {
|
||||
// 1. 查询用户详情(包含企业信息)
|
||||
user, err := s.userAggregateService.GetUserWithEnterpriseInfo(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 构建响应数据
|
||||
item := &responses.UserListItem{
|
||||
ID: user.ID,
|
||||
Phone: user.Phone,
|
||||
UserType: user.UserType,
|
||||
Username: user.Username,
|
||||
IsActive: user.Active,
|
||||
IsCertified: user.IsCertified,
|
||||
LoginCount: user.LoginCount,
|
||||
LastLoginAt: user.LastLoginAt,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
}
|
||||
|
||||
// 添加企业信息
|
||||
if user.EnterpriseInfo != nil {
|
||||
item.EnterpriseInfo = &responses.EnterpriseInfoItem{
|
||||
ID: user.EnterpriseInfo.ID,
|
||||
CompanyName: user.EnterpriseInfo.CompanyName,
|
||||
UnifiedSocialCode: user.EnterpriseInfo.UnifiedSocialCode,
|
||||
LegalPersonName: user.EnterpriseInfo.LegalPersonName,
|
||||
LegalPersonPhone: user.EnterpriseInfo.LegalPersonPhone,
|
||||
EnterpriseAddress: user.EnterpriseInfo.EnterpriseAddress,
|
||||
CreatedAt: user.EnterpriseInfo.CreatedAt,
|
||||
}
|
||||
|
||||
// 获取企业合同信息
|
||||
contracts, err := s.contractService.FindByUserID(ctx, user.ID)
|
||||
if err == nil && len(contracts) > 0 {
|
||||
contractItems := make([]*responses.ContractInfoItem, 0, len(contracts))
|
||||
for _, contract := range contracts {
|
||||
contractItems = append(contractItems, &responses.ContractInfoItem{
|
||||
ID: contract.ID,
|
||||
ContractName: contract.ContractName,
|
||||
ContractType: string(contract.ContractType),
|
||||
ContractTypeName: contract.GetContractTypeName(),
|
||||
ContractFileURL: contract.ContractFileURL,
|
||||
CreatedAt: contract.CreatedAt,
|
||||
})
|
||||
}
|
||||
item.EnterpriseInfo.Contracts = contractItems
|
||||
}
|
||||
}
|
||||
|
||||
// 添加钱包余额信息
|
||||
wallet, err := s.walletService.LoadWalletByUserId(ctx, user.ID)
|
||||
if err == nil && wallet != nil {
|
||||
item.WalletBalance = wallet.Balance.String()
|
||||
} else {
|
||||
item.WalletBalance = "0"
|
||||
}
|
||||
|
||||
return &responses.UserDetailResponse{
|
||||
UserListItem: item,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GetUserStats 获取用户统计信息(管理员功能)
|
||||
// 业务流程:1. 查询用户统计信息 2. 构建响应数据
|
||||
func (s *UserApplicationServiceImpl) GetUserStats(ctx context.Context) (*responses.UserStatsResponse, error) {
|
||||
// 1. 查询用户统计信息
|
||||
stats, err := s.userAggregateService.GetUserStats(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 2. 构建响应数据
|
||||
return &responses.UserStatsResponse{
|
||||
TotalUsers: stats.TotalUsers,
|
||||
ActiveUsers: stats.ActiveUsers,
|
||||
CertifiedUsers: stats.CertifiedUsers,
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user