package system import ( "context" "encoding/json" "errors" "strconv" ) // Dictionary 字典实体 type Dictionary struct { ID uint Name string Type string Status *bool Desc string ParentID *uint Children []*Dictionary } // DictionaryDetail 字典详情实体 type DictionaryDetail struct { ID uint Label string Value string Extend string Status *bool Sort int SysDictionaryID uint ParentID *uint Level int Path string Disabled bool Children []*DictionaryDetail } // DictionaryRepo 字典仓储接口 type DictionaryRepo interface { Create(ctx context.Context, dict *Dictionary) error Update(ctx context.Context, dict *Dictionary) error Delete(ctx context.Context, id uint) error FindByID(ctx context.Context, id uint) (*Dictionary, error) FindByType(ctx context.Context, typ string) (*Dictionary, error) GetByTypeOrID(ctx context.Context, typ string, id uint, status *bool) (*Dictionary, error) List(ctx context.Context, name string) ([]*Dictionary, error) CheckCircularReference(ctx context.Context, currentID, parentID uint) error } // DictionaryDetailRepo 字典详情仓储接口 type DictionaryDetailRepo interface { Create(ctx context.Context, detail *DictionaryDetail) error Update(ctx context.Context, detail *DictionaryDetail) error Delete(ctx context.Context, id uint) error FindByID(ctx context.Context, id uint) (*DictionaryDetail, error) List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*DictionaryDetail, int64, error) GetListByDictionaryID(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error) GetTreeList(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error) GetByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*DictionaryDetail, error) GetByDictionaryIDAndValue(ctx context.Context, dictionaryID uint, value string) (*DictionaryDetail, error) GetByTypeAndValue(ctx context.Context, typ, value string) (*DictionaryDetail, error) GetTreeListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) GetListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) HasChildren(ctx context.Context, id uint) (bool, error) CheckCircularReference(ctx context.Context, id, parentID uint) bool UpdateChildrenLevelAndPath(ctx context.Context, parentID uint) error GetPath(ctx context.Context, id uint) ([]*DictionaryDetail, error) DeleteByDictionaryID(ctx context.Context, dictionaryID uint) error BatchCreate(ctx context.Context, details []*DictionaryDetail) error BatchUpdateParentID(ctx context.Context, idMap map[uint]uint) error } // DictionaryUsecase 字典用例 type DictionaryUsecase struct { repo DictionaryRepo detailRepo DictionaryDetailRepo } // NewDictionaryUsecase 创建字典用例 func NewDictionaryUsecase(repo DictionaryRepo, detailRepo DictionaryDetailRepo) *DictionaryUsecase { return &DictionaryUsecase{repo: repo, detailRepo: detailRepo} } // CreateDictionary 创建字典 func (uc *DictionaryUsecase) CreateDictionary(ctx context.Context, dict *Dictionary) error { // 检查type是否重复 existing, err := uc.repo.FindByType(ctx, dict.Type) if err == nil && existing != nil { return errors.New("存在相同的type,不允许创建") } return uc.repo.Create(ctx, dict) } // UpdateDictionary 更新字典 func (uc *DictionaryUsecase) UpdateDictionary(ctx context.Context, dict *Dictionary) error { old, err := uc.repo.FindByID(ctx, dict.ID) if err != nil { return errors.New("查询字典数据失败") } // 如果type变更,检查是否重复 if old.Type != dict.Type { existing, err := uc.repo.FindByType(ctx, dict.Type) if err == nil && existing != nil { return errors.New("存在相同的type,不允许创建") } } // 检查循环引用 if dict.ParentID != nil && *dict.ParentID != 0 { if err := uc.repo.CheckCircularReference(ctx, dict.ID, *dict.ParentID); err != nil { return err } } return uc.repo.Update(ctx, dict) } // DeleteDictionary 删除字典 func (uc *DictionaryUsecase) DeleteDictionary(ctx context.Context, id uint) error { dict, err := uc.repo.FindByID(ctx, id) if err != nil { return errors.New("请不要搞事") } if err := uc.repo.Delete(ctx, id); err != nil { return err } // 删除关联的字典详情 return uc.detailRepo.DeleteByDictionaryID(ctx, dict.ID) } // GetDictionary 获取字典 func (uc *DictionaryUsecase) GetDictionary(ctx context.Context, typ string, id uint, status *bool) (*Dictionary, error) { return uc.repo.GetByTypeOrID(ctx, typ, id, status) } // GetDictionaryList 获取字典列表 func (uc *DictionaryUsecase) GetDictionaryList(ctx context.Context, name string) ([]*Dictionary, error) { return uc.repo.List(ctx, name) } // ExportDictionary 导出字典 func (uc *DictionaryUsecase) ExportDictionary(ctx context.Context, id uint) (map[string]interface{}, error) { dict, err := uc.repo.FindByID(ctx, id) if err != nil { return nil, err } details, err := uc.detailRepo.GetListByDictionaryID(ctx, dict.ID) if err != nil { return nil, err } // 清理详情数据 var cleanDetails []map[string]interface{} for _, detail := range details { cleanDetail := map[string]interface{}{ "label": detail.Label, "value": detail.Value, "extend": detail.Extend, "status": detail.Status, "sort": detail.Sort, "level": detail.Level, "path": detail.Path, } cleanDetails = append(cleanDetails, cleanDetail) } return map[string]interface{}{ "name": dict.Name, "type": dict.Type, "status": dict.Status, "desc": dict.Desc, "sysDictionaryDetails": cleanDetails, }, nil } // ImportDictionary 导入字典 func (uc *DictionaryUsecase) ImportDictionary(ctx context.Context, jsonStr string) error { var importData struct { Name string `json:"name"` Type string `json:"type"` Status *bool `json:"status"` Desc string `json:"desc"` SysDictionaryDetails []*DictionaryDetail `json:"sysDictionaryDetails"` } if err := json.Unmarshal([]byte(jsonStr), &importData); err != nil { return errors.New("JSON 格式错误: " + err.Error()) } if importData.Name == "" { return errors.New("字典名称不能为空") } if importData.Type == "" { return errors.New("字典类型不能为空") } // 检查type是否重复 existing, err := uc.repo.FindByType(ctx, importData.Type) if err == nil && existing != nil { return errors.New("存在相同的type,不允许导入") } // 创建字典 dict := &Dictionary{ Name: importData.Name, Type: importData.Type, Status: importData.Status, Desc: importData.Desc, } if err := uc.repo.Create(ctx, dict); err != nil { return err } // 处理字典详情 if len(importData.SysDictionaryDetails) > 0 { idMap := make(map[uint]uint) for _, detail := range importData.SysDictionaryDetails { if detail.Label == "" || detail.Value == "" { continue } oldID := detail.ID newDetail := &DictionaryDetail{ Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort, Level: detail.Level, Path: detail.Path, SysDictionaryID: dict.ID, } if err := uc.detailRepo.Create(ctx, newDetail); err != nil { return err } if oldID > 0 { idMap[oldID] = newDetail.ID } } // 更新parent_id关系 if len(idMap) > 0 { if err := uc.detailRepo.BatchUpdateParentID(ctx, idMap); err != nil { return err } } } return nil } // CreateDictionaryDetail 创建字典详情 func (uc *DictionaryUsecase) CreateDictionaryDetail(ctx context.Context, detail *DictionaryDetail) error { // 计算层级和路径 if detail.ParentID != nil && *detail.ParentID != 0 { parent, err := uc.detailRepo.FindByID(ctx, *detail.ParentID) if err != nil { return err } detail.Level = parent.Level + 1 if parent.Path == "" { detail.Path = strconv.Itoa(int(parent.ID)) } else { detail.Path = parent.Path + "," + strconv.Itoa(int(parent.ID)) } } else { detail.Level = 0 detail.Path = "" } return uc.detailRepo.Create(ctx, detail) } // UpdateDictionaryDetail 更新字典详情 func (uc *DictionaryUsecase) UpdateDictionaryDetail(ctx context.Context, detail *DictionaryDetail) error { // 如果更新了父级ID,重新计算层级和路径 if detail.ParentID != nil && *detail.ParentID != 0 { parent, err := uc.detailRepo.FindByID(ctx, *detail.ParentID) if err != nil { return err } // 检查循环引用 if uc.detailRepo.CheckCircularReference(ctx, detail.ID, *detail.ParentID) { return errors.New("不能将字典详情设置为自己或其子项的父级") } detail.Level = parent.Level + 1 if parent.Path == "" { detail.Path = strconv.Itoa(int(parent.ID)) } else { detail.Path = parent.Path + "," + strconv.Itoa(int(parent.ID)) } } else { detail.Level = 0 detail.Path = "" } if err := uc.detailRepo.Update(ctx, detail); err != nil { return err } // 更新所有子项的层级和路径 return uc.detailRepo.UpdateChildrenLevelAndPath(ctx, detail.ID) } // DeleteDictionaryDetail 删除字典详情 func (uc *DictionaryUsecase) DeleteDictionaryDetail(ctx context.Context, id uint) error { hasChildren, err := uc.detailRepo.HasChildren(ctx, id) if err != nil { return err } if hasChildren { return errors.New("该字典详情下还有子项,无法删除") } return uc.detailRepo.Delete(ctx, id) } // GetDictionaryDetail 获取字典详情 func (uc *DictionaryUsecase) GetDictionaryDetail(ctx context.Context, id uint) (*DictionaryDetail, error) { return uc.detailRepo.FindByID(ctx, id) } // GetDictionaryDetailList 获取字典详情列表 func (uc *DictionaryUsecase) GetDictionaryDetailList(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*DictionaryDetail, int64, error) { return uc.detailRepo.List(ctx, page, pageSize, filters) } // GetDictionaryTreeList 获取字典树形列表 func (uc *DictionaryUsecase) GetDictionaryTreeList(ctx context.Context, dictionaryID uint) ([]*DictionaryDetail, error) { return uc.detailRepo.GetTreeList(ctx, dictionaryID) } // GetDictionaryDetailsByParent 根据父级获取字典详情 func (uc *DictionaryUsecase) GetDictionaryDetailsByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*DictionaryDetail, error) { return uc.detailRepo.GetByParent(ctx, dictionaryID, parentID, includeChildren) } // GetDictionaryInfoByValue 根据字典ID和值获取详情 func (uc *DictionaryUsecase) GetDictionaryInfoByValue(ctx context.Context, dictionaryID uint, value string) (*DictionaryDetail, error) { return uc.detailRepo.GetByDictionaryIDAndValue(ctx, dictionaryID, value) } // GetDictionaryInfoByTypeValue 根据字典类型和值获取详情 func (uc *DictionaryUsecase) GetDictionaryInfoByTypeValue(ctx context.Context, typ, value string) (*DictionaryDetail, error) { return uc.detailRepo.GetByTypeAndValue(ctx, typ, value) } // GetDictionaryTreeListByType 根据类型获取树形列表 func (uc *DictionaryUsecase) GetDictionaryTreeListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) { return uc.detailRepo.GetTreeListByType(ctx, typ) } // GetDictionaryListByType 根据类型获取列表 func (uc *DictionaryUsecase) GetDictionaryListByType(ctx context.Context, typ string) ([]*DictionaryDetail, error) { return uc.detailRepo.GetListByType(ctx, typ) } // GetDictionaryPath 获取字典详情路径 func (uc *DictionaryUsecase) GetDictionaryPath(ctx context.Context, id uint) ([]*DictionaryDetail, error) { return uc.detailRepo.GetPath(ctx, id) } // GetDictionaryPathByValue 根据值获取字典详情路径 func (uc *DictionaryUsecase) GetDictionaryPathByValue(ctx context.Context, dictionaryID uint, value string) ([]*DictionaryDetail, error) { detail, err := uc.detailRepo.GetByDictionaryIDAndValue(ctx, dictionaryID, value) if err != nil { return nil, err } return uc.detailRepo.GetPath(ctx, detail.ID) }