320 lines
8.3 KiB
Go
320 lines
8.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/user-management-system/internal/domain"
|
|
"github.com/user-management-system/internal/repository"
|
|
)
|
|
|
|
// CustomFieldService 自定义字段服务
|
|
type CustomFieldService struct {
|
|
fieldRepo *repository.CustomFieldRepository
|
|
valueRepo *repository.UserCustomFieldValueRepository
|
|
}
|
|
|
|
// NewCustomFieldService 创建自定义字段服务
|
|
func NewCustomFieldService(
|
|
fieldRepo *repository.CustomFieldRepository,
|
|
valueRepo *repository.UserCustomFieldValueRepository,
|
|
) *CustomFieldService {
|
|
return &CustomFieldService{
|
|
fieldRepo: fieldRepo,
|
|
valueRepo: valueRepo,
|
|
}
|
|
}
|
|
|
|
// CreateFieldRequest 创建字段请求
|
|
type CreateFieldRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
FieldKey string `json:"field_key" binding:"required"`
|
|
Type int `json:"type" binding:"required"`
|
|
Required bool `json:"required"`
|
|
Default string `json:"default"`
|
|
MinLen int `json:"min_len"`
|
|
MaxLen int `json:"max_len"`
|
|
MinVal float64 `json:"min_val"`
|
|
MaxVal float64 `json:"max_val"`
|
|
Options string `json:"options"`
|
|
Sort int `json:"sort"`
|
|
}
|
|
|
|
// UpdateFieldRequest 更新字段请求
|
|
type UpdateFieldRequest struct {
|
|
Name string `json:"name"`
|
|
Type int `json:"type"`
|
|
Required *bool `json:"required"`
|
|
Default string `json:"default"`
|
|
MinLen int `json:"min_len"`
|
|
MaxLen int `json:"max_len"`
|
|
MinVal float64 `json:"min_val"`
|
|
MaxVal float64 `json:"max_val"`
|
|
Options string `json:"options"`
|
|
Sort int `json:"sort"`
|
|
Status *int `json:"status"`
|
|
}
|
|
|
|
// CreateField 创建自定义字段
|
|
func (s *CustomFieldService) CreateField(ctx context.Context, req *CreateFieldRequest) (*domain.CustomField, error) {
|
|
// 检查field_key是否已存在
|
|
existing, err := s.fieldRepo.GetByFieldKey(ctx, req.FieldKey)
|
|
if err == nil && existing != nil {
|
|
return nil, errors.New("字段标识符已存在")
|
|
}
|
|
|
|
field := &domain.CustomField{
|
|
Name: req.Name,
|
|
FieldKey: req.FieldKey,
|
|
Type: domain.CustomFieldType(req.Type),
|
|
Required: req.Required,
|
|
DefaultVal: req.Default,
|
|
MinLen: req.MinLen,
|
|
MaxLen: req.MaxLen,
|
|
MinVal: req.MinVal,
|
|
MaxVal: req.MaxVal,
|
|
Options: req.Options,
|
|
Sort: req.Sort,
|
|
Status: 1,
|
|
}
|
|
|
|
if err := s.fieldRepo.Create(ctx, field); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return field, nil
|
|
}
|
|
|
|
// UpdateField 更新自定义字段
|
|
func (s *CustomFieldService) UpdateField(ctx context.Context, id int64, req *UpdateFieldRequest) (*domain.CustomField, error) {
|
|
field, err := s.fieldRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return nil, errors.New("字段不存在")
|
|
}
|
|
|
|
if req.Name != "" {
|
|
field.Name = req.Name
|
|
}
|
|
if req.Type > 0 {
|
|
field.Type = domain.CustomFieldType(req.Type)
|
|
}
|
|
if req.Required != nil {
|
|
field.Required = *req.Required
|
|
}
|
|
if req.Default != "" {
|
|
field.DefaultVal = req.Default
|
|
}
|
|
if req.MinLen > 0 {
|
|
field.MinLen = req.MinLen
|
|
}
|
|
if req.MaxLen > 0 {
|
|
field.MaxLen = req.MaxLen
|
|
}
|
|
if req.MinVal > 0 {
|
|
field.MinVal = req.MinVal
|
|
}
|
|
if req.MaxVal > 0 {
|
|
field.MaxVal = req.MaxVal
|
|
}
|
|
if req.Options != "" {
|
|
field.Options = req.Options
|
|
}
|
|
if req.Sort > 0 {
|
|
field.Sort = req.Sort
|
|
}
|
|
if req.Status != nil {
|
|
field.Status = *req.Status
|
|
}
|
|
|
|
if err := s.fieldRepo.Update(ctx, field); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return field, nil
|
|
}
|
|
|
|
// DeleteField 删除自定义字段
|
|
func (s *CustomFieldService) DeleteField(ctx context.Context, id int64) error {
|
|
field, err := s.fieldRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return errors.New("字段不存在")
|
|
}
|
|
|
|
// 删除字段定义
|
|
if err := s.fieldRepo.Delete(ctx, id); err != nil {
|
|
return err
|
|
}
|
|
|
|
// 清理用户的该字段值(可选,取决于业务需求)
|
|
_ = field
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetField 获取自定义字段
|
|
func (s *CustomFieldService) GetField(ctx context.Context, id int64) (*domain.CustomField, error) {
|
|
return s.fieldRepo.GetByID(ctx, id)
|
|
}
|
|
|
|
// ListFields 获取所有启用的自定义字段
|
|
func (s *CustomFieldService) ListFields(ctx context.Context) ([]*domain.CustomField, error) {
|
|
return s.fieldRepo.List(ctx)
|
|
}
|
|
|
|
// ListAllFields 获取所有自定义字段
|
|
func (s *CustomFieldService) ListAllFields(ctx context.Context) ([]*domain.CustomField, error) {
|
|
return s.fieldRepo.ListAll(ctx)
|
|
}
|
|
|
|
// SetUserFieldValue 设置用户的自定义字段值
|
|
func (s *CustomFieldService) SetUserFieldValue(ctx context.Context, userID int64, fieldKey string, value string) error {
|
|
// 获取字段定义
|
|
field, err := s.fieldRepo.GetByFieldKey(ctx, fieldKey)
|
|
if err != nil {
|
|
return errors.New("字段不存在")
|
|
}
|
|
|
|
// 验证值
|
|
if err := s.validateFieldValue(field, value); err != nil {
|
|
return err
|
|
}
|
|
|
|
return s.valueRepo.Set(ctx, userID, field.ID, fieldKey, value)
|
|
}
|
|
|
|
// BatchSetUserFieldValues 批量设置用户的自定义字段值
|
|
func (s *CustomFieldService) BatchSetUserFieldValues(ctx context.Context, userID int64, values map[string]string) error {
|
|
// 获取所有启用的字段定义
|
|
fields, err := s.fieldRepo.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
fieldMap := make(map[string]*domain.CustomField)
|
|
for _, f := range fields {
|
|
fieldMap[f.FieldKey] = f
|
|
}
|
|
|
|
// 验证每个值
|
|
for fieldKey, value := range values {
|
|
field, ok := fieldMap[fieldKey]
|
|
if !ok {
|
|
return fmt.Errorf("字段不存在: %s", fieldKey)
|
|
}
|
|
if err := s.validateFieldValue(field, value); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// 批量设置值
|
|
return s.valueRepo.BatchSet(ctx, userID, values)
|
|
}
|
|
|
|
// GetUserFieldValues 获取用户的所有自定义字段值
|
|
func (s *CustomFieldService) GetUserFieldValues(ctx context.Context, userID int64) ([]*domain.CustomFieldValueResponse, error) {
|
|
// 获取所有启用的字段定义
|
|
fields, err := s.fieldRepo.List(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 获取用户的字段值
|
|
values, err := s.valueRepo.GetByUserID(ctx, userID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 构建字段值映射
|
|
valueMap := make(map[int64]*domain.UserCustomFieldValue)
|
|
for _, v := range values {
|
|
valueMap[v.FieldID] = v
|
|
}
|
|
|
|
// 构建响应
|
|
fieldMap := make(map[string]*domain.CustomField)
|
|
for _, f := range fields {
|
|
fieldMap[f.FieldKey] = f
|
|
}
|
|
|
|
var result []*domain.CustomFieldValueResponse
|
|
for _, field := range fields {
|
|
resp := &domain.CustomFieldValueResponse{
|
|
FieldKey: field.FieldKey,
|
|
}
|
|
|
|
if val, ok := valueMap[field.ID]; ok {
|
|
resp.Value = val.GetValueAsInterface(field)
|
|
} else if field.DefaultVal != "" {
|
|
resp.Value = field.DefaultVal
|
|
} else {
|
|
resp.Value = nil
|
|
}
|
|
|
|
result = append(result, resp)
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// DeleteUserFieldValue 删除用户的自定义字段值
|
|
func (s *CustomFieldService) DeleteUserFieldValue(ctx context.Context, userID int64, fieldKey string) error {
|
|
field, err := s.fieldRepo.GetByFieldKey(ctx, fieldKey)
|
|
if err != nil {
|
|
return errors.New("字段不存在")
|
|
}
|
|
|
|
return s.valueRepo.Delete(ctx, userID, field.ID)
|
|
}
|
|
|
|
// validateFieldValue 验证字段值
|
|
func (s *CustomFieldService) validateFieldValue(field *domain.CustomField, value string) error {
|
|
// 检查必填
|
|
if field.Required && value == "" {
|
|
return errors.New("字段值不能为空")
|
|
}
|
|
|
|
// 如果值为空且有默认值,跳过验证
|
|
if value == "" && field.DefaultVal != "" {
|
|
return nil
|
|
}
|
|
|
|
switch field.Type {
|
|
case domain.CustomFieldTypeString:
|
|
// 字符串长度验证
|
|
if field.MinLen > 0 && len(value) < field.MinLen {
|
|
return fmt.Errorf("值长度不能小于%d", field.MinLen)
|
|
}
|
|
if field.MaxLen > 0 && len(value) > field.MaxLen {
|
|
return fmt.Errorf("值长度不能大于%d", field.MaxLen)
|
|
}
|
|
case domain.CustomFieldTypeNumber:
|
|
// 数字验证
|
|
numVal, err := strconv.ParseFloat(value, 64)
|
|
if err != nil {
|
|
return errors.New("值必须是数字")
|
|
}
|
|
if field.MinVal > 0 && numVal < field.MinVal {
|
|
return fmt.Errorf("值不能小于%.2f", field.MinVal)
|
|
}
|
|
if field.MaxVal > 0 && numVal > field.MaxVal {
|
|
return fmt.Errorf("值不能大于%.2f", field.MaxVal)
|
|
}
|
|
case domain.CustomFieldTypeBoolean:
|
|
// 布尔验证
|
|
if value != "true" && value != "false" && value != "1" && value != "0" {
|
|
return errors.New("值必须是布尔值(true/false/1/0)")
|
|
}
|
|
case domain.CustomFieldTypeDate:
|
|
// 日期验证
|
|
_, err := time.Parse("2006-01-02", value)
|
|
if err != nil {
|
|
return errors.New("值必须是有效的日期格式(YYYY-MM-DD)")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|