This commit is contained in:
2026-08-17 02:12:17 +08:00
parent 560ae46b82
commit 6a05803e08
96 changed files with 2888 additions and 685 deletions
+93 -46
View File
@@ -75,6 +75,10 @@ func (r *dictionaryRepo) CreateDictionary(ctx context.Context, v *biz.Dictionary
}
func (r *dictionaryRepo) ImportDictionary(ctx context.Context, dictionary *biz.Dictionary, details []*biz.DictionaryDetail) error {
var existing dictionaryPO
if err := r.data.gormDB.WithContext(ctx).Where("type = ?", dictionary.Type).First(&existing).Error; !errors.Is(err, gorm.ErrRecordNotFound) {
return errors.New("存在相同的type,不允许导入")
}
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
po := dictionaryPO{Name: dictionary.Name, Type: dictionary.Type, Status: dictionary.Status, Desc: dictionary.Desc, ParentID: dictionary.ParentID}
if err := tx.Create(&po).Error; err != nil {
@@ -183,15 +187,13 @@ func (r *dictionaryRepo) FindDictionary(ctx context.Context, id uint, typ string
}
out := dictionaryFromPO(po)
if details {
out.Details, _, err = r.ListDictionaryDetails(ctx, 0, 0, biz.DictionaryDetailFilter{DictionaryID: out.ID})
if err == nil {
filtered := out.Details[:0]
for _, item := range out.Details {
if item.Status != nil && *item.Status {
filtered = append(filtered, item)
}
}
out.Details = filtered
var detailPOs []dictionaryDetailPO
if err = db.Where("sys_dictionary_id = ? AND status = ?", out.ID, true).Order("sort").Find(&detailPOs).Error; err != nil {
return nil, err
}
out.Details = make([]*biz.DictionaryDetail, 0, len(detailPOs))
for _, detail := range detailPOs {
out.Details = append(out.Details, detailFromPO(detail))
}
}
return out, err
@@ -203,11 +205,14 @@ func (r *dictionaryRepo) ExportDictionary(ctx context.Context, id uint) (*biz.Di
return nil, err
}
value := dictionaryFromPO(po)
details, _, err := r.ListDictionaryDetails(ctx, 0, 0, biz.DictionaryDetailFilter{DictionaryID: id})
if err != nil {
var detailPOs []dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).Where("sys_dictionary_id = ?", id).Order("sort").Find(&detailPOs).Error; err != nil {
return nil, err
}
value.Details = details
value.Details = make([]*biz.DictionaryDetail, 0, len(detailPOs))
for _, detail := range detailPOs {
value.Details = append(value.Details, detailFromPO(detail))
}
return value, nil
}
func (r *dictionaryRepo) ListDictionaries(ctx context.Context, page, size int, name, typ string, details bool) ([]*biz.Dictionary, int64, error) {
@@ -221,19 +226,26 @@ func (r *dictionaryRepo) ListDictionaries(ctx context.Context, page, size int, n
return nil, 0, err
}
var pos []dictionaryPO
if err := applyPagination(db.Order("id"), page, size, 0).Find(&pos).Error; err != nil {
// Both dictionary-list endpoints are intentionally unpaged. The page and
// size parameters remain in the repository seam for existing callers, but
// the administration contract ignores them.
if err := db.Find(&pos).Error; err != nil {
return nil, 0, err
}
parentIDs := make([]uint, 0, len(pos))
dictionaryIDs := make([]uint, 0, len(pos))
for _, po := range pos {
parentIDs = append(parentIDs, po.ID)
dictionaryIDs = append(dictionaryIDs, po.ID)
// The reference list-with-details endpoint only preloads details;
// its ordinary list endpoint preloads one level of dictionary children.
if !details {
parentIDs = append(parentIDs, po.ID)
}
}
childrenByParent := make(map[uint][]dictionaryPO)
if len(parentIDs) > 0 {
if !details && len(parentIDs) > 0 {
var children []dictionaryPO
if err := r.data.gormDB.WithContext(ctx).Where("parent_id IN ?", parentIDs).Order("id").Find(&children).Error; err != nil {
if err := r.data.gormDB.WithContext(ctx).Where("parent_id IN ?", parentIDs).Find(&children).Error; err != nil {
return nil, 0, err
}
for _, child := range children {
@@ -255,13 +267,16 @@ func (r *dictionaryRepo) ListDictionaries(ctx context.Context, page, size int, n
out := make([]*biz.Dictionary, 0, len(pos))
for _, po := range pos {
v := dictionaryFromPO(po)
for _, child := range childrenByParent[po.ID] {
v.Children = append(v.Children, dictionaryFromPO(child))
}
if details {
v.Details = make([]*biz.DictionaryDetail, 0, len(detailsByDictionary[v.ID]))
for _, detail := range detailsByDictionary[v.ID] {
v.Details = append(v.Details, detailFromPO(detail))
}
} else {
v.Children = make([]*biz.Dictionary, 0, len(childrenByParent[po.ID]))
for _, child := range childrenByParent[po.ID] {
v.Children = append(v.Children, dictionaryFromPO(child))
}
}
out = append(out, v)
}
@@ -309,28 +324,25 @@ func (r *dictionaryRepo) UpdateDictionaryDetail(ctx context.Context, v *biz.Dict
level = parent.Level + 1
path = strings.Trim(strings.Join([]string{parent.Path, fmt.Sprint(parent.ID)}, ","), ",")
}
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 r.updateDictionaryDetailChildren(tx, v.ID, level, path)
})
if err := db.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 r.updateDictionaryDetailChildren(db, 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 {
// updateDictionaryDetailChildren recomputes descendants after a move. Updating
// level as well as path matters when a subtree is moved beneath a different depth.
func (r *dictionaryRepo) updateDictionaryDetailChildren(db *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 {
if err := db.Where("parent_id = ?", parentID).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 {
if err := db.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 {
if err := r.updateDictionaryDetailChildren(db, child.ID, parentLevel+1, childPath); err != nil {
return err
}
}
@@ -378,7 +390,7 @@ func (r *dictionaryRepo) ListDictionaryDetails(ctx context.Context, page, size i
return nil, 0, err
}
var pos []dictionaryDetailPO
if err := applyPagination(db.Order("sort,id"), page, size, 100).Find(&pos).Error; err != nil {
if err := applyRequiredPagination(db.Order("sort,id"), page, size, 100).Find(&pos).Error; err != nil {
return nil, 0, err
}
out := make([]*biz.DictionaryDetail, 0, len(pos))
@@ -398,22 +410,57 @@ func (r *dictionaryRepo) DictionaryDetailTree(ctx context.Context, dictionaryID
}
dictionaryID = dictionary.ID
}
items, _, err := r.ListDictionaryDetails(ctx, 0, 0, biz.DictionaryDetailFilter{DictionaryID: dictionaryID})
if err != nil {
var pos []dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).Where("sys_dictionary_id = ? AND parent_id IS NULL", dictionaryID).Order("sort").Find(&pos).Error; err != nil {
return nil, err
}
byID := map[uint]*biz.DictionaryDetail{}
for _, item := range items {
item.Children = []*biz.DictionaryDetail{}
byID[item.ID] = item
}
roots := []*biz.DictionaryDetail{}
for _, item := range items {
if item.ParentID != nil && byID[*item.ParentID] != nil {
byID[*item.ParentID].Children = append(byID[*item.ParentID].Children, item)
} else if item.ParentID == nil {
roots = append(roots, item)
roots := make([]*biz.DictionaryDetail, 0, len(pos))
for _, po := range pos {
item := detailFromPO(po)
if err := r.loadDictionaryDetailChildren(ctx, item); err != nil {
return nil, err
}
roots = append(roots, item)
}
return roots, nil
}
func (r *dictionaryRepo) DictionaryDetailsByParent(ctx context.Context, dictionaryID uint, parentID *uint, includeChildren bool) ([]*biz.DictionaryDetail, error) {
db := r.data.gormDB.WithContext(ctx).Where("sys_dictionary_id = ?", dictionaryID)
if parentID == nil {
db = db.Where("parent_id IS NULL")
} else {
db = db.Where("parent_id = ?", *parentID)
}
var pos []dictionaryDetailPO
if err := db.Order("sort").Find(&pos).Error; err != nil {
return nil, err
}
items := make([]*biz.DictionaryDetail, 0, len(pos))
for _, po := range pos {
item := detailFromPO(po)
if includeChildren {
if err := r.loadDictionaryDetailChildren(ctx, item); err != nil {
return nil, err
}
}
items = append(items, item)
}
return items, nil
}
func (r *dictionaryRepo) loadDictionaryDetailChildren(ctx context.Context, parent *biz.DictionaryDetail) error {
var pos []dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).Where("parent_id = ?", parent.ID).Order("sort").Find(&pos).Error; err != nil {
return err
}
parent.Children = make([]*biz.DictionaryDetail, 0, len(pos))
for _, po := range pos {
child := detailFromPO(po)
if err := r.loadDictionaryDetailChildren(ctx, child); err != nil {
return err
}
parent.Children = append(parent.Children, child)
}
return nil
}