Files
kra-oa/internal/data/dictionary.go
T

258 lines
8.6 KiB
Go

package data
import (
"context"
"errors"
"fmt"
"strings"
"time"
"kra/internal/biz"
"gorm.io/gorm"
)
type dictionaryPO struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
Type string `gorm:"uniqueIndex"`
Status bool
Desc string
ParentID *uint
}
func (dictionaryPO) TableName() string { return "sys_dictionaries" }
type dictionaryDetailPO struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Label string
Value string
Extend string
Status bool
Sort int
DictionaryID uint `gorm:"column:sys_dictionary_id;index"`
ParentID *uint
Level int
Path string
}
func (dictionaryDetailPO) TableName() string { return "sys_dictionary_details" }
func dictionaryFromPO(po dictionaryPO) *biz.Dictionary {
return &biz.Dictionary{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Name: po.Name, Type: po.Type, Status: po.Status, Desc: po.Desc, ParentID: po.ParentID}
}
func detailFromPO(po dictionaryDetailPO) *biz.DictionaryDetail {
return &biz.DictionaryDetail{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Label: po.Label, Value: po.Value, Extend: po.Extend, Status: po.Status, Sort: po.Sort, DictionaryID: po.DictionaryID, ParentID: po.ParentID, Level: po.Level, Path: po.Path}
}
func parameterFromPO(po parameterPO) *biz.SystemParameter {
return &biz.SystemParameter{ID: po.ID, CreatedAt: po.CreatedAt, UpdatedAt: po.UpdatedAt, Name: po.Name, Key: po.Key, Value: po.Value, Desc: po.Desc}
}
func (r *settingsRepo) CreateDictionary(ctx context.Context, v *biz.Dictionary) error {
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
return nil
}
func (r *settingsRepo) 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
}
func (r *settingsRepo) DeleteDictionary(ctx context.Context, id uint) error {
return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
var count int64
if err := tx.Model(&dictionaryPO{}).Where("parent_id = ?", id).Count(&count).Error; err != nil {
return err
}
if count > 0 {
return errors.New("存在子字典不可删除")
}
if err := tx.Where("sys_dictionary_id = ?", id).Delete(&dictionaryDetailPO{}).Error; err != nil {
return err
}
return tx.Delete(&dictionaryPO{}, id).Error
})
}
func (r *settingsRepo) FindDictionary(ctx context.Context, id uint, typ string, details bool) (*biz.Dictionary, error) {
var po dictionaryPO
db := r.data.gormDB.WithContext(ctx)
var err error
if id != 0 {
err = db.First(&po, id).Error
} else {
err = db.Where("type = ?", typ).First(&po).Error
}
if err != nil {
return nil, err
}
out := dictionaryFromPO(po)
if details {
out.Details, _, err = r.ListDictionaryDetails(ctx, 1, 10000, out.ID, "", "")
}
return out, err
}
func (r *settingsRepo) ListDictionaries(ctx context.Context, page, size int, name, typ string, details bool) ([]*biz.Dictionary, int64, error) {
if page < 1 {
page = 1
}
if size < 1 {
size = 10
}
db := r.data.gormDB.WithContext(ctx).Model(&dictionaryPO{})
if name != "" {
db = db.Where("name LIKE ?", "%"+name+"%")
}
if typ != "" {
db = db.Where("type LIKE ?", "%"+typ+"%")
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
var pos []dictionaryPO
if err := db.Order("id desc").Offset((page - 1) * size).Limit(size).Find(&pos).Error; err != nil {
return nil, 0, err
}
out := make([]*biz.Dictionary, 0, len(pos))
for _, po := range pos {
v := dictionaryFromPO(po)
if details {
v.Details, _, _ = r.ListDictionaryDetails(ctx, 1, 10000, v.ID, "", "")
}
out = append(out, v)
}
return out, total, nil
}
func (r *settingsRepo) CreateDictionaryDetail(ctx context.Context, v *biz.DictionaryDetail) error {
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 {
var parent dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&parent, *v.ParentID).Error; err != nil {
return err
}
po.Level = parent.Level + 1
po.Path = strings.Trim(strings.Join([]string{parent.Path, fmt.Sprint(parent.ID)}, ","), ",")
}
if err := r.data.gormDB.WithContext(ctx).Create(&po).Error; err != nil {
return err
}
v.ID = po.ID
v.Level = po.Level
v.Path = po.Path
return nil
}
func (r *settingsRepo) 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 {
return err
}
level, path := 0, ""
if v.ParentID != nil && *v.ParentID != 0 {
if *v.ParentID == v.ID {
return errors.New("不能将自身设为父级")
}
var parent dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&parent, *v.ParentID).Error; err != nil {
return err
}
if strings.Contains(","+parent.Path+",", fmt.Sprintf(",%d,", v.ID)) {
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 {
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
})
}
func (r *settingsRepo) 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 r.data.gormDB.WithContext(ctx).Delete(&dictionaryDetailPO{}, id).Error
}
func (r *settingsRepo) FindDictionaryDetail(ctx context.Context, id uint) (*biz.DictionaryDetail, error) {
var po dictionaryDetailPO
if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil {
return nil, err
}
return detailFromPO(po), nil
}
func (r *settingsRepo) ListDictionaryDetails(ctx context.Context, page, size int, dictionaryID uint, label, value string) ([]*biz.DictionaryDetail, int64, error) {
if page < 1 {
page = 1
}
if size < 1 {
size = 10
}
db := r.data.gormDB.WithContext(ctx).Model(&dictionaryDetailPO{})
if dictionaryID != 0 {
db = db.Where("sys_dictionary_id = ?", dictionaryID)
}
if label != "" {
db = db.Where("label LIKE ?", "%"+label+"%")
}
if value != "" {
db = db.Where("value LIKE ?", "%"+value+"%")
}
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
}
var pos []dictionaryDetailPO
if err := db.Order("sort,id").Offset((page - 1) * size).Limit(size).Find(&pos).Error; err != nil {
return nil, 0, err
}
out := make([]*biz.DictionaryDetail, 0, len(pos))
for _, po := range pos {
out = append(out, detailFromPO(po))
}
return out, total, nil
}
func (r *settingsRepo) DictionaryDetailTree(ctx context.Context, dictionaryID uint, typ string) ([]*biz.DictionaryDetail, error) {
if dictionaryID == 0 {
dictionary, err := r.FindDictionary(ctx, 0, typ, false)
if err != nil {
return nil, err
}
dictionaryID = dictionary.ID
}
items, _, err := r.ListDictionaryDetails(ctx, 1, 100000, dictionaryID, "", "")
if 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 {
roots = append(roots, item)
}
}
return roots, nil
}