package data import ( "context" "errors" "strings" "time" "gorm.io/gorm" "kra/internal/biz" ) type versionPO struct { ID uint `gorm:"primaryKey"` CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` Name string `gorm:"column:version_name"` Code string `gorm:"column:version_code"` Description string Data string `gorm:"column:version_data;type:text"` } func (versionPO) TableName() string { return "sys_versions" } type versionRepo struct{ data *Data } func NewVersionRepo(data *Data) biz.VersionRepo { return &versionRepo{data: data} } func versionFromPO(v versionPO) *biz.Version { return &biz.Version{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, Name: v.Name, Code: v.Code, Description: v.Description, Data: v.Data} } func (r *versionRepo) CreateVersion(ctx context.Context, v *biz.Version) error { po := versionPO{Name: v.Name, Code: v.Code, Description: v.Description, Data: v.Data} if err := r.data.gormDB.WithContext(ctx).Create(&po).Error; err != nil { return err } v.ID = po.ID return nil } func (r *versionRepo) DeleteVersions(ctx context.Context, ids []uint) error { return r.data.gormDB.WithContext(ctx).Delete(&versionPO{}, ids).Error } func (r *versionRepo) FindVersion(ctx context.Context, id uint) (*biz.Version, error) { var po versionPO if err := r.data.gormDB.WithContext(ctx).First(&po, id).Error; err != nil { return nil, err } return versionFromPO(po), nil } func (r *versionRepo) ListVersions(ctx context.Context, page, size int, name, code string, createdAtRange []*time.Time) ([]*biz.Version, int64, error) { db := r.data.gormDB.WithContext(ctx).Model(&versionPO{}) if len(createdAtRange) == 2 && createdAtRange[0] != nil && createdAtRange[1] != nil { db = db.Where("created_at BETWEEN ? AND ?", createdAtRange[0], createdAtRange[1]) } if name != "" { db = db.Where("version_name LIKE ?", "%"+name+"%") } if code != "" { db = db.Where("version_code = ?", code) } var total int64 if err := db.Count(&total).Error; err != nil { return nil, 0, err } var pos []versionPO if err := applyPagination(db, page, size, 100).Find(&pos).Error; err != nil { return nil, 0, err } out := make([]*biz.Version, 0, len(pos)) for _, po := range pos { out = append(out, versionFromPO(po)) } return out, total, nil } func (r *versionRepo) BuildVersionBundle(ctx context.Context, menuIDs, apiIDs, dictIDs []uint) (*biz.VersionBundle, error) { bundle := &biz.VersionBundle{} var menus []menuPO if len(menuIDs) > 0 { if err := r.data.gormDB.WithContext(ctx).Where("id IN ?", menuIDs).Order("sort,id").Find(&menus).Error; err != nil { return nil, err } } byID := map[uint]*biz.Menu{} for _, po := range menus { v := menuFromPO(po) v.Children = []*biz.Menu{} var btns []menuButtonPO _ = r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id = ?", po.ID).Find(&btns).Error for _, btn := range btns { v.Buttons = append(v.Buttons, &biz.MenuButton{Name: btn.Name, Description: btn.Description}) } byID[po.ID] = v } if len(menuIDs) > 0 { var parameters []menuParameterPO if err := r.data.gormDB.WithContext(ctx).Where("sys_base_menu_id IN ?", menuIDs).Find(¶meters).Error; err != nil { return nil, err } for _, parameter := range parameters { if menu := byID[parameter.MenuID]; menu != nil { menu.Parameters = append(menu.Parameters, &biz.MenuParameter{Type: parameter.Type, Key: parameter.Key, Value: parameter.Value}) } } } for _, po := range menus { v := byID[po.ID] if parent := byID[po.ParentID]; parent != nil { parent.Children = append(parent.Children, v) } else if po.ParentID == 0 { bundle.Menus = append(bundle.Menus, v) } } var cleanMenu func(*biz.Menu) cleanMenu = func(menu *biz.Menu) { menu.ID = 0 menu.ParentID = 0 for _, button := range menu.Buttons { button.ID = 0 button.MenuID = 0 button.AuthorityID = 0 } for _, parameter := range menu.Parameters { parameter.ID = 0 parameter.MenuID = 0 } for _, child := range menu.Children { cleanMenu(child) } } for _, menu := range bundle.Menus { cleanMenu(menu) } var apis []apiPO if len(apiIDs) > 0 { if err := r.data.gormDB.WithContext(ctx).Where("id IN ?", apiIDs).Find(&apis).Error; err != nil { return nil, err } } for _, po := range apis { v := apiFromPO(po) v.ID = 0 bundle.APIs = append(bundle.APIs, v) } var dictionaries []dictionaryPO if len(dictIDs) > 0 { if err := r.data.gormDB.WithContext(ctx).Where("id IN ?", dictIDs).Find(&dictionaries).Error; err != nil { return nil, err } } settings := &settingsRepo{data: r.data} for _, po := range dictionaries { v := dictionaryFromPO(po) v.ID = 0 details, _, err := settings.ListDictionaryDetails(ctx, 0, 0, biz.DictionaryDetailFilter{DictionaryID: po.ID}) if err != nil { return nil, err } for _, d := range details { d.ID = 0 d.DictionaryID = 0 d.ParentID = nil d.Path = "" d.Level = 0 } v.Details = details bundle.Dictionaries = append(bundle.Dictionaries, v) } return bundle, nil } func (r *versionRepo) ImportVersionBundle(ctx context.Context, b *biz.VersionBundle) error { return r.data.gormDB.WithContext(ctx).Transaction(func(tx *gorm.DB) error { var addMenus func([]*biz.Menu, uint) error addMenus = func(items []*biz.Menu, parent uint) error { for _, item := range items { var existing menuPO err := tx.Where("name = ? AND path = ?", item.Name, item.Path).First(&existing).Error if errors.Is(err, gorm.ErrRecordNotFound) { po := menuToPO(item) po.ID = 0 po.ParentID = parent if err = tx.Create(&po).Error; err != nil { return err } existing = po for _, button := range item.Buttons { if err = tx.Create(&menuButtonPO{Name: button.Name, Description: button.Description, MenuID: po.ID}).Error; err != nil { return err } } for _, parameter := range item.Parameters { if err = tx.Create(&menuParameterPO{MenuID: po.ID, Type: parameter.Type, Key: parameter.Key, Value: parameter.Value}).Error; err != nil { return err } } } else if err != nil { return err } if err = addMenus(item.Children, existing.ID); err != nil { return err } } return nil } if err := addMenus(b.Menus, 0); err != nil { return err } for _, item := range b.APIs { po := apiPO{Path: item.Path, Description: item.Description, APIGroup: item.APIGroup, Method: strings.ToUpper(item.Method)} if err := tx.Where("path = ? AND method = ?", po.Path, po.Method).FirstOrCreate(&po).Error; err != nil { return err } } for _, item := range b.Dictionaries { var count int64 if err := tx.Model(&dictionaryPO{}).Where("type = ?", item.Type).Count(&count).Error; err != nil { return err } if count > 0 { continue } po := dictionaryPO{Name: item.Name, Type: item.Type, Status: item.Status, Desc: item.Desc} if err := tx.Create(&po).Error; err != nil { return err } for _, detail := range item.Details { d := dictionaryDetailPO{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort, DictionaryID: po.ID} if err := tx.Create(&d).Error; err != nil { return err } } } return nil }) }