package system import ( "context" "errors" "strconv" "kra/internal/biz/system" "kra/internal/data/model" "gorm.io/gorm" ) type dictionaryRepo struct { db *gorm.DB } // NewDictionaryRepo 创建字典仓储 func NewDictionaryRepo(db *gorm.DB) system.DictionaryRepo { return &dictionaryRepo{db: db} } func (r *dictionaryRepo) Create(ctx context.Context, dict *system.Dictionary) error { m := toModelDictionary(dict) if err := r.db.WithContext(ctx).Create(m).Error; err != nil { return err } dict.ID = uint(m.ID) return nil } func (r *dictionaryRepo) Update(ctx context.Context, dict *system.Dictionary) error { updates := map[string]interface{}{ "name": dict.Name, "type": dict.Type, "status": dict.Status, "desc": dict.Desc, "parent_id": dict.ParentID, } return r.db.WithContext(ctx).Model(&model.SysDictionary{}).Where("id = ?", dict.ID).Updates(updates).Error } func (r *dictionaryRepo) Delete(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Delete(&model.SysDictionary{}, id).Error } func (r *dictionaryRepo) FindByID(ctx context.Context, id uint) (*system.Dictionary, error) { var m model.SysDictionary if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil { return nil, err } return toBizDictionary(&m), nil } func (r *dictionaryRepo) FindByType(ctx context.Context, typ string) (*system.Dictionary, error) { var m model.SysDictionary if err := r.db.WithContext(ctx).Where("type = ?", typ).First(&m).Error; err != nil { return nil, err } return toBizDictionary(&m), nil } func (r *dictionaryRepo) GetByTypeOrID(ctx context.Context, typ string, id uint, status *bool) (*system.Dictionary, error) { flag := true if status != nil { flag = *status } var m model.SysDictionary db := r.db.WithContext(ctx).Where("(type = ? OR id = ?) AND status = ?", typ, id, flag) if err := db.First(&m).Error; err != nil { return nil, err } dict := toBizDictionary(&m) // 加载详情 var details []model.SysDictionaryDetail r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND status = ?", m.ID, true).Order("sort").Find(&details) // 详情在service层处理 return dict, nil } func (r *dictionaryRepo) List(ctx context.Context, name string) ([]*system.Dictionary, error) { db := r.db.WithContext(ctx).Model(&model.SysDictionary{}) if name != "" { db = db.Where("name LIKE ? OR type LIKE ?", "%"+name+"%", "%"+name+"%") } // 预加载子字典 db = db.Preload("Children") var list []model.SysDictionary if err := db.Find(&list).Error; err != nil { return nil, err } result := make([]*system.Dictionary, len(list)) for i, m := range list { result[i] = toBizDictionary(&m) } return result, nil } func (r *dictionaryRepo) CheckCircularReference(ctx context.Context, currentID, parentID uint) error { if currentID == parentID { return errors.New("不能将字典设置为自己的父级") } var parent model.SysDictionary if err := r.db.WithContext(ctx).Where("id = ?", parentID).First(&parent).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil } return err } if parent.ParentID != 0 { return r.CheckCircularReference(ctx, currentID, uint(parent.ParentID)) } return nil } type dictionaryDetailRepo struct { db *gorm.DB } // NewDictionaryDetailRepo 创建字典详情仓储 func NewDictionaryDetailRepo(db *gorm.DB) system.DictionaryDetailRepo { return &dictionaryDetailRepo{db: db} } func (r *dictionaryDetailRepo) Create(ctx context.Context, detail *system.DictionaryDetail) error { m := toModelDictionaryDetail(detail) if err := r.db.WithContext(ctx).Create(m).Error; err != nil { return err } detail.ID = uint(m.ID) return nil } func (r *dictionaryDetailRepo) Update(ctx context.Context, detail *system.DictionaryDetail) error { m := toModelDictionaryDetail(detail) return r.db.WithContext(ctx).Save(m).Error } func (r *dictionaryDetailRepo) Delete(ctx context.Context, id uint) error { return r.db.WithContext(ctx).Delete(&model.SysDictionaryDetail{}, id).Error } func (r *dictionaryDetailRepo) FindByID(ctx context.Context, id uint) (*system.DictionaryDetail, error) { var m model.SysDictionaryDetail if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil { return nil, err } return toBizDictionaryDetail(&m), nil } func (r *dictionaryDetailRepo) List(ctx context.Context, page, pageSize int, filters map[string]interface{}) ([]*system.DictionaryDetail, int64, error) { db := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}) if v, ok := filters["label"]; ok && v != "" { db = db.Where("label LIKE ?", "%"+v.(string)+"%") } if v, ok := filters["value"]; ok && v != "" { db = db.Where("value = ?", v) } if v, ok := filters["status"]; ok { db = db.Where("status = ?", v) } if v, ok := filters["sys_dictionary_id"]; ok && v.(uint) != 0 { db = db.Where("sys_dictionary_id = ?", v) } if v, ok := filters["parent_id"]; ok { db = db.Where("parent_id = ?", v) } if v, ok := filters["level"]; ok { db = db.Where("level = ?", v) } var total int64 if err := db.Count(&total).Error; err != nil { return nil, 0, err } offset := (page - 1) * pageSize var list []model.SysDictionaryDetail if err := db.Offset(offset).Limit(pageSize).Order("sort").Order("id").Find(&list).Error; err != nil { return nil, 0, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) } return result, total, nil } func (r *dictionaryDetailRepo) GetListByDictionaryID(ctx context.Context, dictionaryID uint) ([]*system.DictionaryDetail, error) { var list []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ?", dictionaryID).Find(&list).Error; err != nil { return nil, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) } return result, nil } func (r *dictionaryDetailRepo) GetTreeList(ctx context.Context, dictionaryID uint) ([]*system.DictionaryDetail, error) { var list []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND parent_id IS NULL", dictionaryID).Order("sort").Find(&list).Error; err != nil { return nil, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) r.setDisabled(result[i]) if err := r.loadChildren(ctx, result[i]); err != nil { return nil, err } } return result, nil } func (r *dictionaryDetailRepo) loadChildren(ctx context.Context, detail *system.DictionaryDetail) error { var children []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Where("parent_id = ?", detail.ID).Order("sort").Find(&children).Error; err != nil { return err } for _, m := range children { child := toBizDictionaryDetail(&m) r.setDisabled(child) if err := r.loadChildren(ctx, child); err != nil { return err } detail.Children = append(detail.Children, child) } return nil } func (r *dictionaryDetailRepo) setDisabled(detail *system.DictionaryDetail) { if detail.Status != nil { detail.Disabled = !*detail.Status } else { detail.Disabled = false } } func (r *dictionaryDetailRepo) GetByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*system.DictionaryDetail, error) { db := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).Where("sys_dictionary_id = ?", dictionaryID) if parentID != nil { db = db.Where("parent_id = ?", *parentID) } else { db = db.Where("parent_id IS NULL") } var list []model.SysDictionaryDetail if err := db.Order("sort").Find(&list).Error; err != nil { return nil, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) r.setDisabled(result[i]) if includeChildren { if err := r.loadChildren(ctx, result[i]); err != nil { return nil, err } } } return result, nil } func (r *dictionaryDetailRepo) GetByDictionaryIDAndValue(ctx context.Context, dictionaryID uint, value string) (*system.DictionaryDetail, error) { var m model.SysDictionaryDetail if err := r.db.WithContext(ctx).Where("sys_dictionary_id = ? AND value = ?", dictionaryID, value).First(&m).Error; err != nil { return nil, err } return toBizDictionaryDetail(&m), nil } func (r *dictionaryDetailRepo) GetByTypeAndValue(ctx context.Context, typ, value string) (*system.DictionaryDetail, error) { var m model.SysDictionaryDetail if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}). Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id"). Where("sys_dictionaries.type = ? AND sys_dictionary_details.value = ?", typ, value). First(&m).Error; err != nil { return nil, err } return toBizDictionaryDetail(&m), nil } func (r *dictionaryDetailRepo) GetTreeListByType(ctx context.Context, typ string) ([]*system.DictionaryDetail, error) { var list []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}). Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id"). Where("sys_dictionaries.type = ? AND sys_dictionary_details.parent_id IS NULL", typ). Order("sys_dictionary_details.sort"). Find(&list).Error; err != nil { return nil, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) r.setDisabled(result[i]) if err := r.loadChildren(ctx, result[i]); err != nil { return nil, err } } return result, nil } func (r *dictionaryDetailRepo) GetListByType(ctx context.Context, typ string) ([]*system.DictionaryDetail, error) { var list []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}). Joins("JOIN sys_dictionaries ON sys_dictionaries.id = sys_dictionary_details.sys_dictionary_id"). Where("sys_dictionaries.type = ?", typ). Find(&list).Error; err != nil { return nil, err } result := make([]*system.DictionaryDetail, len(list)) for i, m := range list { result[i] = toBizDictionaryDetail(&m) } return result, nil } func (r *dictionaryDetailRepo) HasChildren(ctx context.Context, id uint) (bool, error) { var count int64 if err := r.db.WithContext(ctx).Model(&model.SysDictionaryDetail{}).Where("parent_id = ?", id).Count(&count).Error; err != nil { return false, err } return count > 0, nil } func (r *dictionaryDetailRepo) CheckCircularReference(ctx context.Context, id, parentID uint) bool { if id == parentID { return true } var parent model.SysDictionaryDetail if err := r.db.WithContext(ctx).First(&parent, parentID).Error; err != nil { return false } if parent.ParentID == 0 { return false } return r.CheckCircularReference(ctx, id, uint(parent.ParentID)) } func (r *dictionaryDetailRepo) UpdateChildrenLevelAndPath(ctx context.Context, parentID uint) error { var children []model.SysDictionaryDetail if err := r.db.WithContext(ctx).Where("parent_id = ?", parentID).Find(&children).Error; err != nil { return err } var parent model.SysDictionaryDetail if err := r.db.WithContext(ctx).First(&parent, parentID).Error; err != nil { return err } for _, child := range children { child.Level = parent.Level + 1 if parent.Path == "" { child.Path = strconv.Itoa(int(parent.ID)) } else { child.Path = parent.Path + "," + strconv.Itoa(int(parent.ID)) } if err := r.db.WithContext(ctx).Save(&child).Error; err != nil { return err } if err := r.UpdateChildrenLevelAndPath(ctx, uint(child.ID)); err != nil { return err } } return nil } func (r *dictionaryDetailRepo) GetPath(ctx context.Context, id uint) ([]*system.DictionaryDetail, error) { var m model.SysDictionaryDetail if err := r.db.WithContext(ctx).First(&m, id).Error; err != nil { return nil, err } detail := toBizDictionaryDetail(&m) path := []*system.DictionaryDetail{detail} if m.ParentID != 0 { parentPath, err := r.GetPath(ctx, uint(m.ParentID)) if err != nil { return nil, err } path = append(parentPath, path...) } return path, nil } func (r *dictionaryDetailRepo) DeleteByDictionaryID(ctx context.Context, dictionaryID uint) error { return r.db.WithContext(ctx).Where("sys_dictionary_id = ?", dictionaryID).Delete(&model.SysDictionaryDetail{}).Error } func (r *dictionaryDetailRepo) BatchCreate(ctx context.Context, details []*system.DictionaryDetail) error { models := make([]*model.SysDictionaryDetail, len(details)) for i, d := range details { models[i] = toModelDictionaryDetail(d) } return r.db.WithContext(ctx).Create(&models).Error } func (r *dictionaryDetailRepo) BatchUpdateParentID(ctx context.Context, idMap map[uint]uint) error { // idMap: oldID -> newID // 这里需要根据实际导入逻辑处理 return nil } // 转换函数 func toModelDictionary(d *system.Dictionary) *model.SysDictionary { m := &model.SysDictionary{ ID: int64(d.ID), Name: d.Name, Type: d.Type, Desc: d.Desc, } if d.Status != nil { m.Status = *d.Status } if d.ParentID != nil { m.ParentID = int64(*d.ParentID) } return m } func toBizDictionary(m *model.SysDictionary) *system.Dictionary { d := &system.Dictionary{ ID: uint(m.ID), Name: m.Name, Type: m.Type, Status: &m.Status, Desc: m.Desc, } if m.ParentID != 0 { pid := uint(m.ParentID) d.ParentID = &pid } return d } func toModelDictionaryDetail(d *system.DictionaryDetail) *model.SysDictionaryDetail { m := &model.SysDictionaryDetail{ ID: int64(d.ID), Label: d.Label, Value: d.Value, Extend: d.Extend, Sort: int64(d.Sort), SysDictionaryID: int64(d.SysDictionaryID), Level: int64(d.Level), Path: d.Path, } if d.Status != nil { m.Status = *d.Status } if d.ParentID != nil { m.ParentID = int64(*d.ParentID) } return m } func toBizDictionaryDetail(m *model.SysDictionaryDetail) *system.DictionaryDetail { d := &system.DictionaryDetail{ ID: uint(m.ID), Label: m.Label, Value: m.Value, Extend: m.Extend, Status: &m.Status, Sort: int(m.Sort), SysDictionaryID: uint(m.SysDictionaryID), Level: int(m.Level), Path: m.Path, } if m.ParentID != 0 { pid := uint(m.ParentID) d.ParentID = &pid } return d }