package service import ( "context" "encoding/json" "time" "kra/internal/biz" "kra/internal/service/dto" ) type VersionService struct{ uc *biz.VersionUsecase } func NewVersionService(uc *biz.VersionUsecase) *VersionService { return &VersionService{uc: uc} } type versionExportInfo struct { Name string `json:"name"` Code string `json:"code"` Description string `json:"description"` ExportTime string `json:"exportTime"` } type versionExportMenuParameter struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` SysBaseMenuID uint `json:"SysBaseMenuID"` Type string `json:"type"` Key string `json:"key"` Value string `json:"value"` } type versionExportMenuButton struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` Name string `json:"name"` Description string `json:"desc"` SysBaseMenuID uint `json:"sysBaseMenuID"` } type versionExportMenu struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` ParentID uint `json:"parentId"` Path string `json:"path"` Name string `json:"name"` Hidden bool `json:"hidden"` Component string `json:"component"` Sort int `json:"sort"` Meta dto.VersionMenuMetaRequest `json:"meta"` Authorities []any `json:"authoritys"` Children []*versionExportMenu `json:"children"` Parameters []versionExportMenuParameter `json:"parameters"` MenuButtons []versionExportMenuButton `json:"menuBtn"` } type versionExportAPI struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` Path string `json:"path"` Description string `json:"description"` APIGroup string `json:"apiGroup"` Method string `json:"method"` } type versionExportDictionaryDetail struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` Label string `json:"label"` Value string `json:"value"` Extend string `json:"extend"` Status *bool `json:"status"` Sort int `json:"sort"` DictionaryID int `json:"sysDictionaryID"` ParentID *uint `json:"parentID"` Children []versionExportDictionaryDetail `json:"children"` Level int `json:"level"` Path string `json:"path"` Disabled bool `json:"disabled"` } type versionExportDictionary struct { ID uint `json:"ID"` CreatedAt time.Time `json:"CreatedAt"` UpdatedAt time.Time `json:"UpdatedAt"` Name string `json:"name"` Type string `json:"type"` Status *bool `json:"status"` Desc string `json:"desc"` ParentID *uint `json:"parentID"` Children []versionExportDictionary `json:"children"` Details []versionExportDictionaryDetail `json:"sysDictionaryDetails"` } type versionExportDocument struct { Version versionExportInfo `json:"version"` Menus []*versionExportMenu `json:"menus"` APIs []versionExportAPI `json:"apis"` Dictionaries []versionExportDictionary `json:"dictionaries"` } func exportMenu(value *biz.Menu) *versionExportMenu { menu := &versionExportMenu{ Path: value.Path, Name: value.Name, Hidden: value.Hidden, Component: value.Component, Sort: value.Sort, Meta: dto.VersionMenuMetaRequest{ActiveName: value.ActiveName, KeepAlive: value.KeepAlive, DefaultMenu: value.DefaultMenu, Title: value.Title, Icon: value.Icon, CloseTab: value.CloseTab, TransitionType: value.TransitionType}, } if len(value.Parameters) > 0 { menu.Parameters = make([]versionExportMenuParameter, 0, len(value.Parameters)) for _, parameter := range value.Parameters { menu.Parameters = append(menu.Parameters, versionExportMenuParameter{Type: parameter.Type, Key: parameter.Key, Value: parameter.Value}) } } if len(value.Buttons) > 0 { menu.MenuButtons = make([]versionExportMenuButton, 0, len(value.Buttons)) for _, button := range value.Buttons { menu.MenuButtons = append(menu.MenuButtons, versionExportMenuButton{Name: button.Name, Description: button.Description}) } } if len(value.Children) > 0 { menu.Children = make([]*versionExportMenu, 0, len(value.Children)) for _, child := range value.Children { menu.Children = append(menu.Children, exportMenu(child)) } } return menu } func versionDTO(v *biz.Version) *dto.VersionResponse { return &dto.VersionResponse{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, DeletedAt: nil, VersionName: v.Name, VersionCode: v.Code, Description: v.Description, VersionData: v.Data} } func versionValue(value *string) string { if value == nil { return "" } return *value } func versionPointer(value string) *string { return &value } func (s *VersionService) Versions(ctx context.Context, page, size int, name, code string, createdAtRange []*time.Time) ([]*dto.VersionResponse, int64, error) { items, total, err := s.uc.ListVersions(ctx, page, size, name, code, createdAtRange) if err != nil { return nil, 0, err } out := make([]*dto.VersionResponse, 0, len(items)) for _, v := range items { out = append(out, versionDTO(v)) } return out, total, nil } func (s *VersionService) Version(ctx context.Context, id uint) (*dto.VersionResponse, error) { v, err := s.uc.FindVersion(ctx, id) if err != nil { return nil, err } return versionDTO(v), nil } func (s *VersionService) VersionData(ctx context.Context, id uint) (string, string, error) { v, err := s.uc.FindVersion(ctx, id) if err != nil { return "", "", err } if v.Data != nil && *v.Data != "" { return *v.Data, versionValue(v.Code), nil } payload := versionExportDocument{ Version: versionExportInfo{Name: versionValue(v.Name), Code: versionValue(v.Code), Description: versionValue(v.Description), ExportTime: v.CreatedAt.Format("2006-01-02 15:04:05")}, Menus: []*versionExportMenu{}, APIs: []versionExportAPI{}, } raw, marshalErr := json.MarshalIndent(payload, "", " ") if marshalErr != nil { return "", "", marshalErr } return string(raw), versionValue(v.Code), nil } func (s *VersionService) DeleteVersions(ctx context.Context, ids []uint) error { return s.uc.DeleteVersions(ctx, ids) } func (s *VersionService) Export(ctx context.Context, name, code, description string, menuIDs, apiIDs, dictIDs []uint) error { bundle, err := s.uc.BuildVersionBundle(ctx, menuIDs, apiIDs, dictIDs) if err != nil { return err } bundle.Name = name bundle.Code = code bundle.Description = description bundle.ExportTime = time.Now().Format("2006-01-02 15:04:05") var menus []*versionExportMenu if bundle.Menus != nil { menus = make([]*versionExportMenu, 0, len(bundle.Menus)) for _, value := range bundle.Menus { menus = append(menus, exportMenu(value)) } } apis := make([]versionExportAPI, 0, len(bundle.APIs)) for _, value := range bundle.APIs { apis = append(apis, versionExportAPI{Path: value.Path, Description: value.Description, APIGroup: value.APIGroup, Method: value.Method}) } dictionaries := make([]versionExportDictionary, 0, len(bundle.Dictionaries)) for _, value := range bundle.Dictionaries { details := make([]versionExportDictionaryDetail, 0, len(value.Details)) for _, detail := range value.Details { details = append(details, versionExportDictionaryDetail{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort}) } dictionaries = append(dictionaries, versionExportDictionary{Name: value.Name, Type: value.Type, Status: value.Status, Desc: value.Desc, Details: details}) } payload := versionExportDocument{Version: versionExportInfo{Name: name, Code: code, Description: description, ExportTime: bundle.ExportTime}, Menus: menus, APIs: apis, Dictionaries: dictionaries} raw, err := json.MarshalIndent(payload, "", " ") if err != nil { return &biz.VersionStageError{Stage: biz.VersionStageJSON, Err: err} } if err = s.uc.CreateVersion(ctx, &biz.Version{Name: versionPointer(name), Code: versionPointer(code), Description: versionPointer(description), Data: versionPointer(string(raw))}); err != nil { return &biz.VersionStageError{Stage: biz.VersionStageSave, Err: err} } return nil } func (s *VersionService) Import(ctx context.Context, bundle *biz.VersionBundle) error { return s.uc.ImportVersionBundle(ctx, bundle) } func versionMenuDomain(value dto.VersionMenuRequest) *biz.Menu { menu := &biz.Menu{Path: value.Path, Name: value.Name, Hidden: value.Hidden, Component: value.Component, Sort: value.Sort, ActiveName: value.Meta.ActiveName, KeepAlive: value.Meta.KeepAlive, DefaultMenu: value.Meta.DefaultMenu, Title: value.Meta.Title, Icon: value.Meta.Icon, CloseTab: value.Meta.CloseTab, TransitionType: value.Meta.TransitionType} for _, button := range value.MenuButtons { menu.Buttons = append(menu.Buttons, &biz.MenuButton{Name: button.Name, Description: button.Description}) } for _, parameter := range value.Parameters { menu.Parameters = append(menu.Parameters, &biz.MenuParameter{Type: parameter.Type, Key: parameter.Key, Value: parameter.Value}) } for _, child := range value.Children { menu.Children = append(menu.Children, versionMenuDomain(child)) } return menu } func (s *VersionService) ImportRequest(ctx context.Context, req *dto.ImportVersionRequest) error { if req.Version.Name == "" || req.Version.Code == "" { return biz.ErrInvalidVersion } bundle := &biz.VersionBundle{Name: req.Version.Name, Code: req.Version.Code, Description: req.Version.Description, ExportTime: req.Version.ExportTime} for _, menu := range req.Menus { bundle.Menus = append(bundle.Menus, versionMenuDomain(menu)) } for _, api := range req.APIs { bundle.APIs = append(bundle.APIs, &biz.API{Path: api.Path, Description: api.Description, APIGroup: api.APIGroup, Method: api.Method}) } for _, dictionary := range req.Dictionaries { item := &biz.Dictionary{Name: dictionary.Name, Type: dictionary.Type, Status: dictionary.Status, Desc: dictionary.Description} for _, detail := range dictionary.Details { item.Details = append(item.Details, &biz.DictionaryDetail{Label: detail.Label, Value: detail.Value, Extend: detail.Extend, Status: detail.Status, Sort: detail.Sort, ParentID: detail.ParentID, Level: detail.Level, Path: detail.Path}) } bundle.Dictionaries = append(bundle.Dictionaries, item) } if err := s.Import(ctx, bundle); err != nil { return err } raw, _ := json.Marshal(req) _ = s.uc.CreateVersion(ctx, &biz.Version{ Name: versionPointer(req.Version.Name), Code: versionPointer(req.Version.Code + "_imported_" + time.Now().Format("20060102150405")), Description: versionPointer("导入版本: " + req.Version.Description), Data: versionPointer(string(raw)), }) return nil }