This commit is contained in:
2025-07-28 01:46:39 +08:00
parent b03129667a
commit 357639462a
219 changed files with 21634 additions and 8138 deletions

View File

@@ -0,0 +1,317 @@
package entities
import (
"fmt"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// ContractType 合同类型枚举
type ContractType string
const (
ContractTypeCooperation ContractType = "cooperation" // 合作协议
)
// ContractInfo 合同信息聚合根
// 存储企业签署的合同信息,一个企业可以有多个合同
type ContractInfo struct {
// 基础标识
ID string `gorm:"primaryKey;type:varchar(36)" json:"id" comment:"合同信息唯一标识"`
EnterpriseInfoID string `gorm:"type:varchar(36);not null;index" json:"enterprise_info_id" comment:"关联企业信息ID"`
UserID string `gorm:"type:varchar(36);not null;index" json:"user_id" comment:"关联用户ID"`
// 合同基本信息
ContractName string `gorm:"type:varchar(255);not null" json:"contract_name" comment:"合同名称"`
ContractType ContractType `gorm:"type:varchar(50);not null;index" json:"contract_type" comment:"合同类型"`
ContractFileID string `gorm:"type:varchar(100);not null" json:"contract_file_id" comment:"合同文件ID"`
ContractFileURL string `gorm:"type:varchar(500);not null" json:"contract_file_url" comment:"合同文件下载链接"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at" comment:"更新时间"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-" comment:"软删除时间"`
// 关联关系
EnterpriseInfo *EnterpriseInfo `gorm:"foreignKey:EnterpriseInfoID" json:"enterprise_info,omitempty" comment:"关联的企业信息"`
// 领域事件 (不持久化)
domainEvents []interface{} `gorm:"-" json:"-"`
}
// TableName 指定数据库表名
func (ContractInfo) TableName() string {
return "contract_infos"
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (c *ContractInfo) BeforeCreate(tx *gorm.DB) error {
if c.ID == "" {
c.ID = uuid.New().String()
}
return nil
}
// ================ 工厂方法 ================
// NewContractInfo 创建新的合同信息
func NewContractInfo(enterpriseInfoID, userID, contractName string, contractType ContractType, contractFileID, contractFileURL string) (*ContractInfo, error) {
if enterpriseInfoID == "" {
return nil, fmt.Errorf("企业信息ID不能为空")
}
if userID == "" {
return nil, fmt.Errorf("用户ID不能为空")
}
if contractName == "" {
return nil, fmt.Errorf("合同名称不能为空")
}
if contractType == "" {
return nil, fmt.Errorf("合同类型不能为空")
}
if contractFileID == "" {
return nil, fmt.Errorf("合同文件ID不能为空")
}
if contractFileURL == "" {
return nil, fmt.Errorf("合同文件URL不能为空")
}
// 验证合同类型
if !isValidContractType(contractType) {
return nil, fmt.Errorf("无效的合同类型: %s", contractType)
}
contractInfo := &ContractInfo{
ID: uuid.New().String(),
EnterpriseInfoID: enterpriseInfoID,
UserID: userID,
ContractName: contractName,
ContractType: contractType,
ContractFileID: contractFileID,
ContractFileURL: contractFileURL,
domainEvents: make([]interface{}, 0),
}
// 添加领域事件
contractInfo.addDomainEvent(&ContractInfoCreatedEvent{
ContractInfoID: contractInfo.ID,
EnterpriseInfoID: enterpriseInfoID,
UserID: userID,
ContractName: contractName,
ContractType: string(contractType),
CreatedAt: time.Now(),
})
return contractInfo, nil
}
// ================ 聚合根核心方法 ================
// UpdateContractInfo 更新合同信息
func (c *ContractInfo) UpdateContractInfo(contractName, contractFileID, contractFileURL string) error {
// 验证输入参数
if contractName == "" {
return fmt.Errorf("合同名称不能为空")
}
if contractFileID == "" {
return fmt.Errorf("合同文件ID不能为空")
}
if contractFileURL == "" {
return fmt.Errorf("合同文件URL不能为空")
}
// 记录原始值用于事件
oldContractName := c.ContractName
oldContractFileID := c.ContractFileID
// 更新字段
c.ContractName = contractName
c.ContractFileID = contractFileID
c.ContractFileURL = contractFileURL
// 添加领域事件
c.addDomainEvent(&ContractInfoUpdatedEvent{
ContractInfoID: c.ID,
EnterpriseInfoID: c.EnterpriseInfoID,
UserID: c.UserID,
OldContractName: oldContractName,
NewContractName: contractName,
OldContractFileID: oldContractFileID,
NewContractFileID: contractFileID,
UpdatedAt: time.Now(),
})
return nil
}
// DeleteContract 删除合同
func (c *ContractInfo) DeleteContract() error {
// 添加领域事件
c.addDomainEvent(&ContractInfoDeletedEvent{
ContractInfoID: c.ID,
EnterpriseInfoID: c.EnterpriseInfoID,
UserID: c.UserID,
ContractName: c.ContractName,
ContractType: string(c.ContractType),
DeletedAt: time.Now(),
})
return nil
}
// ================ 业务规则验证 ================
// ValidateBusinessRules 验证业务规则
func (c *ContractInfo) ValidateBusinessRules() error {
// 基础字段验证
if err := c.validateBasicFields(); err != nil {
return fmt.Errorf("基础字段验证失败: %w", err)
}
// 业务规则验证
if err := c.validateBusinessLogic(); err != nil {
return fmt.Errorf("业务规则验证失败: %w", err)
}
return nil
}
// validateBasicFields 验证基础字段
func (c *ContractInfo) validateBasicFields() error {
if c.EnterpriseInfoID == "" {
return fmt.Errorf("企业信息ID不能为空")
}
if c.UserID == "" {
return fmt.Errorf("用户ID不能为空")
}
if c.ContractName == "" {
return fmt.Errorf("合同名称不能为空")
}
if c.ContractType == "" {
return fmt.Errorf("合同类型不能为空")
}
if c.ContractFileID == "" {
return fmt.Errorf("合同文件ID不能为空")
}
if c.ContractFileURL == "" {
return fmt.Errorf("合同文件URL不能为空")
}
// 合同类型验证
if !isValidContractType(c.ContractType) {
return fmt.Errorf("无效的合同类型: %s", c.ContractType)
}
return nil
}
// validateBusinessLogic 验证业务逻辑
func (c *ContractInfo) validateBusinessLogic() error {
// 合同名称长度限制
if len(c.ContractName) > 255 {
return fmt.Errorf("合同名称长度不能超过255个字符")
}
// 合同文件URL格式验证
if !isValidURL(c.ContractFileURL) {
return fmt.Errorf("合同文件URL格式无效")
}
return nil
}
// ================ 查询方法 ================
// GetContractTypeName 获取合同类型名称
func (c *ContractInfo) GetContractTypeName() string {
switch c.ContractType {
case ContractTypeCooperation:
return "合作协议"
default:
return "未知类型"
}
}
// IsCooperationContract 检查是否为合作协议
func (c *ContractInfo) IsCooperationContract() bool {
return c.ContractType == ContractTypeCooperation
}
// ================ 领域事件管理 ================
// addDomainEvent 添加领域事件
func (c *ContractInfo) addDomainEvent(event interface{}) {
if c.domainEvents == nil {
c.domainEvents = make([]interface{}, 0)
}
c.domainEvents = append(c.domainEvents, event)
}
// GetDomainEvents 获取领域事件
func (c *ContractInfo) GetDomainEvents() []interface{} {
return c.domainEvents
}
// ClearDomainEvents 清除领域事件
func (c *ContractInfo) ClearDomainEvents() {
c.domainEvents = make([]interface{}, 0)
}
// ================ 私有验证方法 ================
// isValidContractType 验证合同类型
func isValidContractType(contractType ContractType) bool {
switch contractType {
case ContractTypeCooperation:
return true
default:
return false
}
}
// isValidURL 验证URL格式
func isValidURL(url string) bool {
// 简单的URL格式验证
if len(url) < 10 {
return false
}
if url[:7] != "http://" && url[:8] != "https://" {
return false
}
return true
}
// ================ 领域事件定义 ================
// ContractInfoCreatedEvent 合同信息创建事件
type ContractInfoCreatedEvent struct {
ContractInfoID string `json:"contract_info_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
UserID string `json:"user_id"`
ContractName string `json:"contract_name"`
ContractType string `json:"contract_type"`
CreatedAt time.Time `json:"created_at"`
}
// ContractInfoUpdatedEvent 合同信息更新事件
type ContractInfoUpdatedEvent struct {
ContractInfoID string `json:"contract_info_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
UserID string `json:"user_id"`
OldContractName string `json:"old_contract_name"`
NewContractName string `json:"new_contract_name"`
OldContractFileID string `json:"old_contract_file_id"`
NewContractFileID string `json:"new_contract_file_id"`
UpdatedAt time.Time `json:"updated_at"`
}
// ContractInfoDeletedEvent 合同信息删除事件
type ContractInfoDeletedEvent struct {
ContractInfoID string `json:"contract_info_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
UserID string `json:"user_id"`
ContractName string `json:"contract_name"`
ContractType string `json:"contract_type"`
DeletedAt time.Time `json:"deleted_at"`
}

View File

@@ -2,13 +2,14 @@ package entities
import (
"fmt"
"strings"
"time"
"github.com/google/uuid"
"gorm.io/gorm"
)
// EnterpriseInfo 企业信息实体
// EnterpriseInfo 企业信息聚合根
// 存储用户在认证过程中验证后的企业信息,认证完成后不可修改
// 与用户是一对一关系,每个用户最多对应一个企业信息
type EnterpriseInfo struct {
@@ -22,6 +23,8 @@ type EnterpriseInfo struct {
LegalPersonName string `gorm:"type:varchar(100);not null" json:"legal_person_name" comment:"法定代表人姓名"`
LegalPersonID string `gorm:"type:varchar(50);not null" json:"legal_person_id" comment:"法定代表人身份证号"`
LegalPersonPhone string `gorm:"type:varchar(50);not null" json:"legal_person_phone" comment:"法定代表人手机号"`
EnterpriseAddress string `json:"enterprise_address" gorm:"type:varchar(200);not null" comment:"企业地址"`
EnterpriseEmail string `json:"enterprise_email" gorm:"type:varchar(100);not null" comment:"企业邮箱"`
// 时间戳字段
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at" comment:"创建时间"`
@@ -30,6 +33,9 @@ type EnterpriseInfo struct {
// 关联关系
User *User `gorm:"foreignKey:UserID" json:"user,omitempty" comment:"关联的用户信息"`
// 领域事件 (不持久化)
domainEvents []interface{} `gorm:"-" json:"-"`
}
// TableName 指定数据库表名
@@ -37,28 +43,6 @@ func (EnterpriseInfo) TableName() string {
return "enterprise_infos"
}
// IsComplete 检查企业四要素是否完整
// 验证企业名称、统一社会信用代码、法定代表人姓名、身份证号是否都已填写
func (e *EnterpriseInfo) IsComplete() bool {
return e.CompanyName != "" &&
e.UnifiedSocialCode != "" &&
e.LegalPersonName != "" &&
e.LegalPersonID != ""
}
// Validate 验证企业信息是否有效
// 这里可以添加企业信息的业务验证逻辑
// 比如统一社会信用代码格式验证、身份证号格式验证等
func (e *EnterpriseInfo) Validate() error {
if !e.IsComplete() {
return fmt.Errorf("企业信息不完整")
}
// 这里可以添加企业信息的业务验证逻辑
// 比如统一社会信用代码格式验证、身份证号格式验证等
return nil
}
// BeforeCreate GORM钩子创建前自动生成UUID
func (e *EnterpriseInfo) BeforeCreate(tx *gorm.DB) error {
if e.ID == "" {
@@ -66,3 +50,327 @@ func (e *EnterpriseInfo) BeforeCreate(tx *gorm.DB) error {
}
return nil
}
// ================ 工厂方法 ================
// NewEnterpriseInfo 创建新的企业信息
func NewEnterpriseInfo(userID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone,enterpriseAddress, enterpriseEmail string) (*EnterpriseInfo, error) {
if userID == "" {
return nil, fmt.Errorf("用户ID不能为空")
}
if companyName == "" {
return nil, fmt.Errorf("企业名称不能为空")
}
if unifiedSocialCode == "" {
return nil, fmt.Errorf("统一社会信用代码不能为空")
}
if legalPersonName == "" {
return nil, fmt.Errorf("法定代表人姓名不能为空")
}
if legalPersonID == "" {
return nil, fmt.Errorf("法定代表人身份证号不能为空")
}
if legalPersonPhone == "" {
return nil, fmt.Errorf("法定代表人手机号不能为空")
}
if enterpriseAddress == "" {
return nil, fmt.Errorf("企业地址不能为空")
}
if enterpriseEmail == "" {
return nil, fmt.Errorf("企业邮箱不能为空")
}
enterpriseInfo := &EnterpriseInfo{
ID: uuid.New().String(),
UserID: userID,
CompanyName: companyName,
UnifiedSocialCode: unifiedSocialCode,
LegalPersonName: legalPersonName,
LegalPersonID: legalPersonID,
LegalPersonPhone: legalPersonPhone,
EnterpriseAddress: enterpriseAddress,
EnterpriseEmail: enterpriseEmail,
domainEvents: make([]interface{}, 0),
}
// 添加领域事件
enterpriseInfo.addDomainEvent(&EnterpriseInfoCreatedEvent{
EnterpriseInfoID: enterpriseInfo.ID,
UserID: userID,
CompanyName: companyName,
UnifiedSocialCode: unifiedSocialCode,
CreatedAt: time.Now(),
})
return enterpriseInfo, nil
}
// ================ 聚合根核心方法 ================
// UpdateEnterpriseInfo 更新企业信息
func (e *EnterpriseInfo) UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress, enterpriseEmail string) error {
// 验证输入参数
if companyName == "" {
return fmt.Errorf("企业名称不能为空")
}
if unifiedSocialCode == "" {
return fmt.Errorf("统一社会信用代码不能为空")
}
if legalPersonName == "" {
return fmt.Errorf("法定代表人姓名不能为空")
}
if legalPersonID == "" {
return fmt.Errorf("法定代表人身份证号不能为空")
}
if legalPersonPhone == "" {
return fmt.Errorf("法定代表人手机号不能为空")
}
if enterpriseAddress == "" {
return fmt.Errorf("企业地址不能为空")
}
if enterpriseEmail == "" {
return fmt.Errorf("企业邮箱不能为空")
}
// 记录原始值用于事件
oldCompanyName := e.CompanyName
oldUnifiedSocialCode := e.UnifiedSocialCode
// 更新字段
e.CompanyName = companyName
e.UnifiedSocialCode = unifiedSocialCode
e.LegalPersonName = legalPersonName
e.LegalPersonID = legalPersonID
e.LegalPersonPhone = legalPersonPhone
e.EnterpriseAddress = enterpriseAddress
e.EnterpriseEmail = enterpriseEmail
// 添加领域事件
e.addDomainEvent(&EnterpriseInfoUpdatedEvent{
EnterpriseInfoID: e.ID,
UserID: e.UserID,
OldCompanyName: oldCompanyName,
NewCompanyName: companyName,
OldUnifiedSocialCode: oldUnifiedSocialCode,
NewUnifiedSocialCode: unifiedSocialCode,
UpdatedAt: time.Now(),
})
return nil
}
// ================ 业务规则验证 ================
// ValidateBusinessRules 验证业务规则
func (e *EnterpriseInfo) ValidateBusinessRules() error {
// 基础字段验证
if err := e.validateBasicFields(); err != nil {
return fmt.Errorf("基础字段验证失败: %w", err)
}
// 业务规则验证
if err := e.validateBusinessLogic(); err != nil {
return fmt.Errorf("业务规则验证失败: %w", err)
}
return nil
}
// validateBasicFields 验证基础字段
func (e *EnterpriseInfo) validateBasicFields() error {
if e.UserID == "" {
return fmt.Errorf("用户ID不能为空")
}
if e.CompanyName == "" {
return fmt.Errorf("企业名称不能为空")
}
if e.UnifiedSocialCode == "" {
return fmt.Errorf("统一社会信用代码不能为空")
}
if e.LegalPersonName == "" {
return fmt.Errorf("法定代表人姓名不能为空")
}
if e.LegalPersonID == "" {
return fmt.Errorf("法定代表人身份证号不能为空")
}
if e.LegalPersonPhone == "" {
return fmt.Errorf("法定代表人手机号不能为空")
}
if e.EnterpriseEmail == "" {
return fmt.Errorf("企业邮箱不能为空")
}
// 统一社会信用代码格式验证
if !e.isValidUnifiedSocialCode(e.UnifiedSocialCode) {
return fmt.Errorf("统一社会信用代码格式无效")
}
// 身份证号格式验证
if !e.isValidIDCard(e.LegalPersonID) {
return fmt.Errorf("法定代表人身份证号格式无效")
}
// 手机号格式验证
if !e.isValidPhone(e.LegalPersonPhone) {
return fmt.Errorf("法定代表人手机号格式无效")
}
// 邮箱格式验证 (简单示例,实际应更严格)
if !e.isValidEmail(e.EnterpriseEmail) {
return fmt.Errorf("企业邮箱格式无效")
}
return nil
}
// validateBusinessLogic 验证业务逻辑
func (e *EnterpriseInfo) validateBusinessLogic() error {
// 企业名称长度限制
if len(e.CompanyName) > 255 {
return fmt.Errorf("企业名称长度不能超过255个字符")
}
// 法定代表人姓名长度限制
if len(e.LegalPersonName) > 100 {
return fmt.Errorf("法定代表人姓名长度不能超过100个字符")
}
// 企业邮箱格式验证 (简单示例,实际应更严格)
if !e.isValidEmail(e.EnterpriseEmail) {
return fmt.Errorf("企业邮箱格式无效")
}
return nil
}
// ================ 查询方法 ================
// IsComplete 检查企业四要素是否完整
func (e *EnterpriseInfo) IsComplete() bool {
return e.CompanyName != "" &&
e.UnifiedSocialCode != "" &&
e.LegalPersonName != "" &&
e.LegalPersonID != "" &&
e.LegalPersonPhone != "" &&
e.EnterpriseEmail != ""
}
// GetCertificationProgress 获取认证进度
func (e *EnterpriseInfo) GetCertificationProgress() int {
if e.IsComplete() {
return 100
}
return 50
}
// GetCertificationStatus 获取认证状态描述
func (e *EnterpriseInfo) GetCertificationStatus() string {
if e.IsComplete() {
return "信息完整"
}
return "信息不完整"
}
// CanUpdate 检查是否可以更新
func (e *EnterpriseInfo) CanUpdate() bool {
return true
}
// ================ 领域事件管理 ================
// addDomainEvent 添加领域事件
func (e *EnterpriseInfo) addDomainEvent(event interface{}) {
if e.domainEvents == nil {
e.domainEvents = make([]interface{}, 0)
}
e.domainEvents = append(e.domainEvents, event)
}
// GetDomainEvents 获取领域事件
func (e *EnterpriseInfo) GetDomainEvents() []interface{} {
return e.domainEvents
}
// ClearDomainEvents 清除领域事件
func (e *EnterpriseInfo) ClearDomainEvents() {
e.domainEvents = make([]interface{}, 0)
}
// ================ 私有验证方法 ================
// isValidUnifiedSocialCode 验证统一社会信用代码格式
func (e *EnterpriseInfo) isValidUnifiedSocialCode(code string) bool {
// 统一社会信用代码为18位
if len(code) != 18 {
return false
}
// 这里可以添加更详细的格式验证逻辑
return true
}
// isValidIDCard 验证身份证号格式
func (e *EnterpriseInfo) isValidIDCard(id string) bool {
// 身份证号为18位
if len(id) != 18 {
return false
}
// 这里可以添加更详细的格式验证逻辑
return true
}
// isValidPhone 验证手机号格式
func (e *EnterpriseInfo) isValidPhone(phone string) bool {
// 手机号格式验证
if len(phone) != 11 {
return false
}
// 这里可以添加更详细的格式验证逻辑
return true
}
// isValidEmail 验证邮箱格式
func (e *EnterpriseInfo) isValidEmail(email string) bool {
// 简单的邮箱格式验证,实际应更严格
if len(email) > 255 || len(email) < 3 { // 长度限制
return false
}
if !strings.Contains(email, "@") {
return false
}
if !strings.Contains(email, ".") {
return false
}
return true
}
// ================ 领域事件定义 ================
// EnterpriseInfoCreatedEvent 企业信息创建事件
type EnterpriseInfoCreatedEvent struct {
EnterpriseInfoID string `json:"enterprise_info_id"`
UserID string `json:"user_id"`
CompanyName string `json:"company_name"`
UnifiedSocialCode string `json:"unified_social_code"`
CreatedAt time.Time `json:"created_at"`
}
// EnterpriseInfoUpdatedEvent 企业信息更新事件
type EnterpriseInfoUpdatedEvent struct {
EnterpriseInfoID string `json:"enterprise_info_id"`
UserID string `json:"user_id"`
OldCompanyName string `json:"old_company_name"`
NewCompanyName string `json:"new_company_name"`
OldUnifiedSocialCode string `json:"old_unified_social_code"`
NewUnifiedSocialCode string `json:"new_unified_social_code"`
UpdatedAt time.Time `json:"updated_at"`
}

View File

@@ -1,12 +1,13 @@
package entities
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"regexp"
"time"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
"gorm.io/gorm"
)
@@ -18,7 +19,7 @@ const (
UserTypeAdmin UserType = "admin" // 管理员
)
// User 用户实体
// User 用户聚合根
// 系统用户的核心信息,提供基础的账户管理功能
// 支持手机号登录密码加密存储实现Entity接口便于统一管理
type User struct {
@@ -33,6 +34,7 @@ type User struct {
// 管理员特有字段
Active bool `gorm:"default:true" json:"is_active" comment:"账户是否激活"`
IsCertified bool `gorm:"default:false" json:"is_certified" comment:"是否完成认证"`
LastLoginAt *time.Time `json:"last_login_at" comment:"最后登录时间"`
LoginCount int `gorm:"default:0" json:"login_count" comment:"登录次数统计"`
Permissions string `gorm:"type:text" json:"permissions" comment:"权限列表(JSON格式存储)"`
@@ -44,6 +46,9 @@ type User struct {
// 关联关系
EnterpriseInfo *EnterpriseInfo `gorm:"foreignKey:UserID" json:"enterprise_info,omitempty" comment:"企业信息(认证后获得)"`
// 领域事件 (不持久化)
domainEvents []interface{} `gorm:"-" json:"-"`
}
// BeforeCreate GORM钩子创建前自动生成UUID
@@ -85,14 +90,305 @@ func (u *User) Validate() error {
return NewValidationError("手机号格式无效")
}
// 验证密码强度
if err := u.validatePasswordStrength(u.Password); err != nil {
return nil
}
// CompleteCertification 完成认证
func (u *User) CompleteCertification() error {
u.IsCertified = true
return nil
}
// ================ 企业信息管理方法 ================
// CreateEnterpriseInfo 创建企业信息
func (u *User) CreateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress, enterpriseEmail string) error {
// 检查是否已有企业信息
if u.EnterpriseInfo != nil {
return fmt.Errorf("用户已有企业信息")
}
// 创建企业信息实体
enterpriseInfo, err := NewEnterpriseInfo(u.ID, companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress, enterpriseEmail)
if err != nil {
return fmt.Errorf("创建企业信息失败: %w", err)
}
// 设置关联关系
u.EnterpriseInfo = enterpriseInfo
// 添加领域事件
u.addDomainEvent(&UserEnterpriseInfoCreatedEvent{
UserID: u.ID,
EnterpriseInfoID: enterpriseInfo.ID,
CompanyName: companyName,
UnifiedSocialCode: unifiedSocialCode,
CreatedAt: time.Now(),
})
return nil
}
// UpdateEnterpriseInfo 更新企业信息
func (u *User) UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress, enterpriseEmail string) error {
// 检查是否有企业信息
if u.EnterpriseInfo == nil {
return fmt.Errorf("用户暂无企业信息")
}
// 记录原始值用于事件
oldCompanyName := u.EnterpriseInfo.CompanyName
oldUnifiedSocialCode := u.EnterpriseInfo.UnifiedSocialCode
// 更新企业信息
err := u.EnterpriseInfo.UpdateEnterpriseInfo(companyName, unifiedSocialCode, legalPersonName, legalPersonID, legalPersonPhone, enterpriseAddress, enterpriseEmail)
if err != nil {
return err
}
// 添加领域事件
u.addDomainEvent(&UserEnterpriseInfoUpdatedEvent{
UserID: u.ID,
EnterpriseInfoID: u.EnterpriseInfo.ID,
OldCompanyName: oldCompanyName,
NewCompanyName: companyName,
OldUnifiedSocialCode: oldUnifiedSocialCode,
NewUnifiedSocialCode: unifiedSocialCode,
UpdatedAt: time.Now(),
})
return nil
}
// GetEnterpriseInfo 获取企业信息
func (u *User) GetEnterpriseInfo() *EnterpriseInfo {
return u.EnterpriseInfo
}
// HasEnterpriseInfo 检查是否有企业信息
func (u *User) HasEnterpriseInfo() bool {
return u.EnterpriseInfo != nil
}
// RemoveEnterpriseInfo 移除企业信息
func (u *User) RemoveEnterpriseInfo() error {
if u.EnterpriseInfo == nil {
return fmt.Errorf("用户暂无企业信息")
}
enterpriseInfoID := u.EnterpriseInfo.ID
u.EnterpriseInfo = nil
// 添加领域事件
u.addDomainEvent(&UserEnterpriseInfoRemovedEvent{
UserID: u.ID,
EnterpriseInfoID: enterpriseInfoID,
RemovedAt: time.Now(),
})
return nil
}
// ValidateEnterpriseInfo 验证企业信息
func (u *User) ValidateEnterpriseInfo() error {
if u.EnterpriseInfo == nil {
return fmt.Errorf("用户暂无企业信息")
}
return u.EnterpriseInfo.ValidateBusinessRules()
}
// ================ 聚合根核心方法 ================
// Register 用户注册
func (u *User) Register() error {
// 验证用户信息
if err := u.Validate(); err != nil {
return fmt.Errorf("用户信息验证失败: %w", err)
}
// 添加领域事件
u.addDomainEvent(&UserRegisteredEvent{
UserID: u.ID,
Phone: u.Phone,
UserType: u.UserType,
CreatedAt: time.Now(),
})
return nil
}
// Login 用户登录
func (u *User) Login(ipAddress, userAgent string) error {
// 检查用户是否可以登录
if !u.CanLogin() {
return fmt.Errorf("用户无法登录")
}
// 更新登录信息
u.UpdateLastLoginAt()
u.IncrementLoginCount()
// 添加领域事件
u.addDomainEvent(&UserLoggedInEvent{
UserID: u.ID,
Phone: u.Phone,
IPAddress: ipAddress,
UserAgent: userAgent,
LoginAt: time.Now(),
})
return nil
}
// ChangePassword 修改密码
func (u *User) ChangePassword(oldPassword, newPassword, confirmPassword string) error {
// 验证旧密码
if !u.CheckPassword(oldPassword) {
return fmt.Errorf("原密码错误")
}
// 验证新密码
if newPassword != confirmPassword {
return fmt.Errorf("两次输入的密码不一致")
}
// 设置新密码
if err := u.SetPassword(newPassword); err != nil {
return fmt.Errorf("设置新密码失败: %w", err)
}
// 添加领域事件
u.addDomainEvent(&UserPasswordChangedEvent{
UserID: u.ID,
Phone: u.Phone,
ChangedAt: time.Now(),
})
return nil
}
// ActivateUser 激活用户
func (u *User) ActivateUser() error {
if u.Active {
return fmt.Errorf("用户已经是激活状态")
}
u.Activate()
// 添加领域事件
u.addDomainEvent(&UserActivatedEvent{
UserID: u.ID,
Phone: u.Phone,
ActivatedAt: time.Now(),
})
return nil
}
// DeactivateUser 停用用户
func (u *User) DeactivateUser() error {
if !u.Active {
return fmt.Errorf("用户已经是停用状态")
}
u.Deactivate()
// 添加领域事件
u.addDomainEvent(&UserDeactivatedEvent{
UserID: u.ID,
Phone: u.Phone,
DeactivatedAt: time.Now(),
})
return nil
}
// ================ 业务规则验证 ================
// ValidateBusinessRules 验证业务规则
func (u *User) ValidateBusinessRules() error {
// 1. 基础字段验证
if err := u.validateBasicFields(); err != nil {
return fmt.Errorf("基础字段验证失败: %w", err)
}
// 2. 业务规则验证
if err := u.validateBusinessLogic(); err != nil {
return fmt.Errorf("业务规则验证失败: %w", err)
}
// 3. 状态一致性验证
if err := u.validateStateConsistency(); err != nil {
return fmt.Errorf("状态一致性验证失败: %w", err)
}
return nil
}
// validateBasicFields 验证基础字段
func (u *User) validateBasicFields() error {
if u.Phone == "" {
return fmt.Errorf("手机号不能为空")
}
if u.Password == "" {
return fmt.Errorf("密码不能为空")
}
// 验证手机号格式
if !u.IsValidPhone() {
return fmt.Errorf("手机号格式无效")
}
// 不对加密后的hash做长度校验
return nil
}
// validateBusinessLogic 验证业务逻辑
func (u *User) validateBusinessLogic() error {
// 管理员用户必须有用户名
// if u.IsAdmin() && u.Username == "" {
// return fmt.Errorf("管理员用户必须有用户名")
// }
// // 普通用户不能有用户名
// if u.IsNormalUser() && u.Username != "" {
// return fmt.Errorf("普通用户不能有用户名")
// }
return nil
}
// validateStateConsistency 验证状态一致性
func (u *User) validateStateConsistency() error {
// 如果用户被删除,不能是激活状态
if u.IsDeleted() && u.Active {
return fmt.Errorf("已删除用户不能是激活状态")
}
return nil
}
// ================ 领域事件管理 ================
// addDomainEvent 添加领域事件
func (u *User) addDomainEvent(event interface{}) {
if u.domainEvents == nil {
u.domainEvents = make([]interface{}, 0)
}
u.domainEvents = append(u.domainEvents, event)
}
// GetDomainEvents 获取领域事件
func (u *User) GetDomainEvents() []interface{} {
return u.domainEvents
}
// ClearDomainEvents 清除领域事件
func (u *User) ClearDomainEvents() {
u.domainEvents = make([]interface{}, 0)
}
// ================ 业务方法 ================
// IsAdmin 检查是否为管理员
@@ -131,81 +427,30 @@ func (u *User) Deactivate() {
u.Active = false
}
// ChangePassword 修改密码
// 验证旧密码,检查新密码强度,更新密码
func (u *User) ChangePassword(oldPassword, newPassword, confirmPassword string) error {
// 1. 验证确认密码
if newPassword != confirmPassword {
return NewValidationError("新密码和确认新密码不匹配")
}
// 2. 验证旧密码
if !u.CheckPassword(oldPassword) {
return NewValidationError("当前密码错误")
}
// 3. 验证新密码强度
if err := u.validatePasswordStrength(newPassword); err != nil {
return err
}
// 4. 检查新密码不能与旧密码相同
if u.CheckPassword(newPassword) {
return NewValidationError("新密码不能与当前密码相同")
}
// 5. 更新密码
hashedPassword, err := u.hashPassword(newPassword)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
u.Password = hashedPassword
return nil
}
// CheckPassword 验证密码是否正确
func (u *User) CheckPassword(password string) bool {
err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
return err == nil
return u.Password == hashPassword(password)
}
// SetPassword 设置密码(用于注册或重置密码)
func (u *User) SetPassword(password string) error {
// 验证密码强度
// 只对明文做强度校
if err := u.validatePasswordStrength(password); err != nil {
return err
}
// 加密密码
hashedPassword, err := u.hashPassword(password)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
u.Password = hashedPassword
u.Password = hashPassword(password)
return nil
}
// ResetPassword 重置密码(忘记密码时使用)
func (u *User) ResetPassword(newPassword, confirmPassword string) error {
// 1. 验证确认密码
if newPassword != confirmPassword {
return NewValidationError("新密码和确认新密码不匹配")
}
// 2. 验证新密码强度
if err := u.validatePasswordStrength(newPassword); err != nil {
return err
}
// 3. 更新密码
hashedPassword, err := u.hashPassword(newPassword)
if err != nil {
return fmt.Errorf("密码加密失败: %w", err)
}
u.Password = hashedPassword
u.Password = hashPassword(newPassword)
return nil
}
@@ -265,16 +510,14 @@ func (u *User) GetMaskedPhone() string {
// ================ 私有方法 ================
// hashPassword 加密密码
func (u *User) hashPassword(password string) (string, error) {
hashedBytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
return string(hashedBytes), nil
// hashPassword 使用sha256+hex加密密码
func hashPassword(password string) string {
h := sha256.New()
h.Write([]byte(password))
return hex.EncodeToString(h.Sum(nil))
}
// validatePasswordStrength 验证密码强度
// validatePasswordStrength 只对明文做长度/强度校
func (u *User) validatePasswordStrength(password string) error {
if len(password) < 6 {
return NewValidationError("密码长度不能少于6位")
@@ -347,59 +590,69 @@ func IsValidationError(err error) bool {
return ok
}
// ================ 缓存相关 ================
// ================ 领域事件定义 ================
type UserCache struct {
// 基础标识
ID string `json:"id" comment:"用户唯一标识"`
Phone string `json:"phone" comment:"手机号码(登录账号)"`
Password string `json:"password" comment:"登录密码(加密存储)"`
UserType string `json:"user_type" comment:"用户类型"`
Username string `json:"username" comment:"用户名"`
Active bool `gorm:"default:true" json:"is_active" comment:"账户是否激活"`
LastLoginAt *time.Time `json:"last_login_at" comment:"最后登录时间"`
LoginCount int `gorm:"default:0" json:"login_count" comment:"登录次数统计"`
Permissions string `gorm:"type:text" json:"permissions" comment:"权限列表(JSON格式存储)"`
// 时间戳字段
CreatedAt time.Time `json:"created_at" comment:"创建时间"`
UpdatedAt time.Time `json:"updated_at" comment:"更新时间"`
DeletedAt gorm.DeletedAt `json:"deleted_at" comment:"软删除时间"`
// UserRegisteredEvent 用户注册事件
type UserRegisteredEvent struct {
UserID string `json:"user_id"`
Phone string `json:"phone"`
UserType string `json:"user_type"`
CreatedAt time.Time `json:"created_at"`
}
// ToCache 转换为缓存结构
func (u *User) ToCache() *UserCache {
return &UserCache{
ID: u.ID,
Phone: u.Phone,
Password: u.Password,
UserType: u.UserType,
Username: u.Username,
CreatedAt: u.CreatedAt,
UpdatedAt: u.UpdatedAt,
DeletedAt: u.DeletedAt,
// 补充所有字段
// 管理员特有字段
Active: u.Active,
LastLoginAt: u.LastLoginAt,
LoginCount: u.LoginCount,
Permissions: u.Permissions,
}
// UserLoggedInEvent 用户登录事件
type UserLoggedInEvent struct {
UserID string `json:"user_id"`
Phone string `json:"phone"`
IPAddress string `json:"ip_address"`
UserAgent string `json:"user_agent"`
LoginAt time.Time `json:"login_at"`
}
// FromCache 从缓存结构恢复
func (u *User) FromCache(cache *UserCache) {
u.ID = cache.ID
u.Phone = cache.Phone
u.Password = cache.Password
u.UserType = cache.UserType
u.Username = cache.Username
u.CreatedAt = cache.CreatedAt
u.UpdatedAt = cache.UpdatedAt
u.DeletedAt = cache.DeletedAt
u.Active = cache.Active
u.LastLoginAt = cache.LastLoginAt
u.LoginCount = cache.LoginCount
u.Permissions = cache.Permissions
// UserPasswordChangedEvent 用户密码修改事件
type UserPasswordChangedEvent struct {
UserID string `json:"user_id"`
Phone string `json:"phone"`
ChangedAt time.Time `json:"changed_at"`
}
// UserActivatedEvent 用户激活事件
type UserActivatedEvent struct {
UserID string `json:"user_id"`
Phone string `json:"phone"`
ActivatedAt time.Time `json:"activated_at"`
}
// UserDeactivatedEvent 用户停用事件
type UserDeactivatedEvent struct {
UserID string `json:"user_id"`
Phone string `json:"phone"`
DeactivatedAt time.Time `json:"deactivated_at"`
}
// UserEnterpriseInfoCreatedEvent 企业信息创建事件
type UserEnterpriseInfoCreatedEvent struct {
UserID string `json:"user_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
CompanyName string `json:"company_name"`
UnifiedSocialCode string `json:"unified_social_code"`
CreatedAt time.Time `json:"created_at"`
}
// UserEnterpriseInfoUpdatedEvent 企业信息更新事件
type UserEnterpriseInfoUpdatedEvent struct {
UserID string `json:"user_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
OldCompanyName string `json:"old_company_name"`
NewCompanyName string `json:"new_company_name"`
OldUnifiedSocialCode string `json:"old_unified_social_code"`
NewUnifiedSocialCode string `json:"new_unified_social_code"`
UpdatedAt time.Time `json:"updated_at"`
}
// UserEnterpriseInfoRemovedEvent 企业信息移除事件
type UserEnterpriseInfoRemovedEvent struct {
UserID string `json:"user_id"`
EnterpriseInfoID string `json:"enterprise_info_id"`
RemovedAt time.Time `json:"removed_at"`
}