This commit is contained in:
2026-08-16 09:02:39 +08:00
parent c554152f4f
commit f7f6db8695
105 changed files with 2535 additions and 948 deletions
+80 -15
View File
@@ -23,7 +23,7 @@ type dictionaryPO struct {
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
Type string
Status bool
Status *bool
Desc string
ParentID *uint
}
@@ -38,7 +38,7 @@ type dictionaryDetailPO struct {
Label string
Value string
Extend string
Status bool
Status *bool
Sort int
DictionaryID uint `gorm:"column:sys_dictionary_id;index"`
ParentID *uint
@@ -59,11 +59,18 @@ func parameterFromPO(po parameterPO) *biz.SystemParameter {
}
func (r *dictionaryRepo) CreateDictionary(ctx context.Context, v *biz.Dictionary) error {
var existing dictionaryPO
if err := r.data.gormDB.WithContext(ctx).Where("type = ?", v.Type).First(&existing).Error; err == nil {
return errors.New("存在相同的type,不允许创建")
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
po := dictionaryPO{Name: v.Name, Type: v.Type, Status: v.Status, Desc: v.Desc, ParentID: v.ParentID}
if err := r.data.gormDB.WithContext(ctx).Create(&po).Error; err != nil {
return err
}
v.ID = po.ID
v.CreatedAt, v.UpdatedAt = po.CreatedAt, po.UpdatedAt
return nil
}
@@ -108,7 +115,46 @@ func (r *dictionaryRepo) ImportDictionary(ctx context.Context, dictionary *biz.D
})
}
func (r *dictionaryRepo) UpdateDictionary(ctx context.Context, v *biz.Dictionary) error {
return r.data.gormDB.WithContext(ctx).Model(&dictionaryPO{}).Where("id = ?", v.ID).Updates(map[string]any{"name": v.Name, "type": v.Type, "status": v.Status, "desc": v.Desc, "parent_id": v.ParentID}).Error
db := r.data.gormDB.WithContext(ctx)
var current dictionaryPO
if err := db.Where("id = ?", v.ID).First(&current).Error; err != nil {
return errors.New("查询字典数据失败")
}
if current.Type != v.Type {
var duplicate dictionaryPO
if err := db.Where("type = ?", v.Type).First(&duplicate).Error; err == nil {
return errors.New("存在相同的type,不允许创建")
} else if !errors.Is(err, gorm.ErrRecordNotFound) {
return err
}
}
if v.ParentID != nil && *v.ParentID != 0 {
if err := r.checkDictionaryCircularReference(ctx, v.ID, *v.ParentID); err != nil {
return err
}
}
return db.Model(&current).Updates(map[string]any{"name": v.Name, "type": v.Type, "status": v.Status, "desc": v.Desc, "parent_id": v.ParentID}).Error
}
// checkDictionaryCircularReference mirrors the compatible recursive parent-chain
// check. A missing parent is allowed (the reference implementation permits a
// dangling parent ID); only a self-reference or an ancestor cycle is rejected.
func (r *dictionaryRepo) checkDictionaryCircularReference(ctx context.Context, currentID, parentID uint) error {
if currentID == parentID {
return errors.New("不能将字典设置为自己的父级")
}
var parent dictionaryPO
err := r.data.gormDB.WithContext(ctx).Where("id = ?", parentID).First(&parent).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil
}
if err != nil {
return err
}
if parent.ParentID != nil && *parent.ParentID != 0 {
return r.checkDictionaryCircularReference(ctx, currentID, *parent.ParentID)
}
return nil
}
func (r *dictionaryRepo) DeleteDictionary(ctx context.Context, id uint) error {
db := r.data.gormDB.WithContext(ctx)
@@ -141,7 +187,7 @@ func (r *dictionaryRepo) FindDictionary(ctx context.Context, id uint, typ string
if err == nil {
filtered := out.Details[:0]
for _, item := range out.Details {
if item.Status {
if item.Status != nil && *item.Status {
filtered = append(filtered, item)
}
}
@@ -226,7 +272,7 @@ func (r *dictionaryRepo) CreateDictionaryDetail(ctx context.Context, v *biz.Dict
po := dictionaryDetailPO{Label: v.Label, Value: v.Value, Extend: v.Extend, Status: v.Status, Sort: v.Sort, DictionaryID: v.DictionaryID, ParentID: v.ParentID}
po.Level = 0
po.Path = ""
if v.ParentID != nil && *v.ParentID != 0 {
if v.ParentID != nil {
var parent dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&parent, *v.ParentID).Error; err != nil {
return err
@@ -244,40 +290,59 @@ func (r *dictionaryRepo) CreateDictionaryDetail(ctx context.Context, v *biz.Dict
}
func (r *dictionaryRepo) UpdateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
var po dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&po, v.ID).Error; err != nil {
db := r.data.gormDB.WithContext(ctx)
if err := db.First(&po, v.ID).Error; err != nil {
return err
}
level, path := 0, ""
if v.ParentID != nil && *v.ParentID != 0 {
if v.ParentID != nil {
if *v.ParentID == v.ID {
return errors.New("不能将自身设为父级")
return errors.New("不能将字典详情设置为自己或其子项的父级")
}
var parent dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&parent, *v.ParentID).Error; err != nil {
if err := db.First(&parent, *v.ParentID).Error; err != nil {
return err
}
if strings.Contains(","+parent.Path+",", fmt.Sprintf(",%d,", v.ID)) {
return errors.New("不能移动到自己的子级")
return errors.New("不能将字典详情设置为自己或其子项的父级")
}
level = parent.Level + 1
path = strings.Trim(strings.Join([]string{parent.Path, fmt.Sprint(parent.ID)}, ","), ",")
}
oldPrefix := strings.Trim(strings.Join([]string{po.Path, fmt.Sprint(po.ID)}, ","), ",")
newPrefix := strings.Trim(strings.Join([]string{path, fmt.Sprint(po.ID)}, ","), ",")
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
return db.Transaction(func(tx *gorm.DB) error {
if err := tx.Model(&dictionaryDetailPO{}).Where("id = ?", v.ID).Updates(map[string]any{"label": v.Label, "value": v.Value, "extend": v.Extend, "status": v.Status, "sort": v.Sort, "sys_dictionary_id": v.DictionaryID, "parent_id": v.ParentID, "level": level, "path": path}).Error; err != nil {
return err
}
return tx.Model(&dictionaryDetailPO{}).Where("path = ? OR path LIKE ?", oldPrefix, oldPrefix+",%").Update("path", gorm.Expr("REPLACE(path, ?, ?)", oldPrefix, newPrefix)).Error
return r.updateDictionaryDetailChildren(tx, v.ID, level, path)
})
}
// updateDictionaryDetailChildren recomputes descendants after a move, as the
// The service does this recursively. Updating level as well as path matters when a
// subtree is moved beneath a different depth.
func (r *dictionaryRepo) updateDictionaryDetailChildren(tx *gorm.DB, parentID uint, parentLevel int, parentPath string) error {
var children []dictionaryDetailPO
if err := tx.Where("parent_id = ?", parentID).Order("sort,id").Find(&children).Error; err != nil {
return err
}
for _, child := range children {
childPath := strings.Trim(strings.Join([]string{parentPath, fmt.Sprint(parentID)}, ","), ",")
if err := tx.Model(&dictionaryDetailPO{}).Where("id = ?", child.ID).Updates(map[string]any{"level": parentLevel + 1, "path": childPath}).Error; err != nil {
return err
}
if err := r.updateDictionaryDetailChildren(tx, child.ID, parentLevel+1, childPath); err != nil {
return err
}
}
return nil
}
func (r *dictionaryRepo) DeleteDictionaryDetail(ctx context.Context, id uint) error {
var count int64
if err := r.data.gormDB.WithContext(ctx).Model(&dictionaryDetailPO{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
return err
}
if count > 0 {
return errors.New("存在子级不可删除")
return errors.New("该字典详情下还有子项,无法删除")
}
return r.data.gormDB.WithContext(ctx).Delete(&dictionaryDetailPO{}, id).Error
}