mirror of
https://github.com/APIParkLab/APIPark.git
synced 2026-06-14 20:41:15 +08:00
677 lines
18 KiB
Go
677 lines
18 KiB
Go
package catalogue
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
service_overview "github.com/APIParkLab/APIPark/service/service-overview"
|
|
|
|
mcp_server "github.com/APIParkLab/APIPark/mcp-server"
|
|
|
|
"github.com/APIParkLab/APIPark/module/monitor/driver"
|
|
|
|
"github.com/APIParkLab/APIPark/service/monitor"
|
|
|
|
"github.com/APIParkLab/APIPark/service/setting"
|
|
|
|
"github.com/eolinker/eosc/log"
|
|
|
|
"github.com/APIParkLab/APIPark/gateway"
|
|
"github.com/APIParkLab/APIPark/service/cluster"
|
|
|
|
api_doc "github.com/APIParkLab/APIPark/service/api-doc"
|
|
|
|
service_doc "github.com/APIParkLab/APIPark/service/service-doc"
|
|
|
|
service_tag "github.com/APIParkLab/APIPark/service/service-tag"
|
|
|
|
"github.com/APIParkLab/APIPark/service/subscribe"
|
|
|
|
"github.com/eolinker/go-common/store"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/eolinker/go-common/utils"
|
|
|
|
"github.com/APIParkLab/APIPark/service/release"
|
|
|
|
"github.com/APIParkLab/APIPark/service/api"
|
|
"github.com/eolinker/go-common/auto"
|
|
|
|
"github.com/APIParkLab/APIPark/service/tag"
|
|
|
|
"github.com/APIParkLab/APIPark/service/service"
|
|
|
|
"github.com/google/uuid"
|
|
|
|
"github.com/APIParkLab/APIPark/service/catalogue"
|
|
|
|
catalogue_dto "github.com/APIParkLab/APIPark/module/catalogue/dto"
|
|
)
|
|
|
|
var (
|
|
_ ICatalogueModule = (*imlCatalogueModule)(nil)
|
|
_sortMax = math.MaxInt32 / 2
|
|
)
|
|
|
|
type imlCatalogueModule struct {
|
|
catalogueService catalogue.ICatalogueService `autowired:""`
|
|
apiService api.IAPIService `autowired:""`
|
|
apiDocService api_doc.IAPIDocService `autowired:""`
|
|
serviceService service.IServiceService `autowired:""`
|
|
serviceOverviewService service_overview.IOverviewService `autowired:""`
|
|
serviceTagService service_tag.ITagService `autowired:""`
|
|
serviceDocService service_doc.IDocService `autowired:""`
|
|
tagService tag.ITagService `autowired:""`
|
|
releaseService release.IReleaseService `autowired:""`
|
|
subscribeService subscribe.ISubscribeService `autowired:""`
|
|
subscribeApplyService subscribe.ISubscribeApplyService `autowired:""`
|
|
transaction store.ITransaction `autowired:""`
|
|
clusterService cluster.IClusterService `autowired:""`
|
|
settingService setting.ISettingService `autowired:""`
|
|
monitorService monitor.IMonitorService `autowired:""`
|
|
root *Root
|
|
}
|
|
|
|
func (i *imlCatalogueModule) DefaultCatalogue(ctx context.Context) (*catalogue_dto.Catalogue, error) {
|
|
catalogues, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, v := range catalogues {
|
|
if v.Parent == "" {
|
|
return &catalogue_dto.Catalogue{
|
|
Id: v.Id,
|
|
Name: v.Name,
|
|
Parent: v.Parent,
|
|
Sort: v.Sort,
|
|
}, nil
|
|
}
|
|
}
|
|
return nil, errors.New("no default catalogue")
|
|
}
|
|
|
|
func (i *imlCatalogueModule) onlineSubscriber(ctx context.Context, clusterId string, sub *gateway.SubscribeRelease) error {
|
|
client, err := i.clusterService.GatewayClient(ctx, clusterId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
_ = client.Close(ctx)
|
|
}()
|
|
return client.Subscribe().Online(ctx, sub)
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Get(ctx context.Context, id string) (*catalogue_dto.Catalogue, error) {
|
|
info, err := i.catalogueService.Get(ctx, id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &catalogue_dto.Catalogue{
|
|
Id: info.Id,
|
|
Name: info.Name,
|
|
Parent: info.Parent,
|
|
Sort: info.Sort,
|
|
}, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) ExportAll(ctx context.Context) ([]*catalogue_dto.ExportCatalogue, error) {
|
|
list, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return utils.SliceToSlice(list, func(c *catalogue.Catalogue) *catalogue_dto.ExportCatalogue {
|
|
return &catalogue_dto.ExportCatalogue{
|
|
Id: c.Id,
|
|
Name: c.Name,
|
|
Parent: c.Parent,
|
|
Sort: c.Sort,
|
|
}
|
|
}), nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) getExecutor(ctx context.Context, clusterId string) (driver.IExecutor, error) {
|
|
info, err := i.monitorService.GetByCluster(ctx, clusterId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return driver.CreateExecutor(info.Driver, info.Config)
|
|
}
|
|
|
|
func (i *imlCatalogueModule) statistics(ctx context.Context, clusterId string, groupBy string, start, end time.Time, wheres []monitor.MonWhereItem, limit int) (map[string]monitor.MonCommonData, error) {
|
|
executor, err := i.getExecutor(ctx, clusterId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
result, err := executor.CommonStatistics(ctx, start, end, groupBy, limit, wheres)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) genCommonWheres(ctx context.Context, clusterIds ...string) ([]monitor.MonWhereItem, error) {
|
|
|
|
clusters, err := i.clusterService.List(ctx, clusterIds...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
clusterIds = utils.SliceToSlice(clusters, func(item *cluster.Cluster) string {
|
|
return item.Uuid
|
|
})
|
|
|
|
wheres := make([]monitor.MonWhereItem, 0, 1)
|
|
nodes, err := i.clusterService.Nodes(ctx, clusterIds...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
nodeIds := utils.SliceToSlice(nodes, func(s *cluster.Node) string {
|
|
return s.Name
|
|
})
|
|
wheres = append(wheres, monitor.MonWhereItem{
|
|
Key: "node",
|
|
Operation: "in",
|
|
Values: nodeIds,
|
|
})
|
|
|
|
return wheres, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) ProviderStatistics(ctx context.Context, start, end time.Time, serviceIds ...string) (map[string]int64, error) {
|
|
// 判断是否配置influxdb
|
|
clusterId := cluster.DefaultClusterID
|
|
_, err := i.monitorService.Get(ctx, clusterId)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return make(map[string]int64), nil
|
|
}
|
|
return nil, err
|
|
}
|
|
_, err = i.clusterService.Get(ctx, clusterId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
wheres, err := i.genCommonWheres(ctx, clusterId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if len(serviceIds) > 0 {
|
|
wheres = append(wheres, monitor.MonWhereItem{
|
|
Key: "provider",
|
|
Operation: "in",
|
|
Values: serviceIds,
|
|
})
|
|
}
|
|
statisticMap, err := i.statistics(ctx, clusterId, "provider", start, end, wheres, 0)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
resultMap := make(map[string]int64)
|
|
for key, item := range statisticMap {
|
|
resultMap[key] = item.RequestTotal
|
|
}
|
|
|
|
return resultMap, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Subscribe(ctx context.Context, subscribeInfo *catalogue_dto.SubscribeService) error {
|
|
if len(subscribeInfo.Applications) == 0 {
|
|
return fmt.Errorf("applications is empty")
|
|
}
|
|
// 获取服务的基本信息
|
|
s, err := i.serviceService.Get(ctx, subscribeInfo.Service)
|
|
if err != nil {
|
|
return fmt.Errorf("get service failed: %w", err)
|
|
}
|
|
if !s.AsServer {
|
|
return fmt.Errorf("service does not support subscribe")
|
|
}
|
|
|
|
userId := utils.UserId(ctx)
|
|
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
|
|
apps := make([]string, 0, len(subscribeInfo.Applications))
|
|
|
|
for _, appId := range subscribeInfo.Applications {
|
|
if appId == s.Id {
|
|
// 不能订阅自己
|
|
continue
|
|
}
|
|
|
|
appInfo, err := i.serviceService.Get(ctx, appId)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !appInfo.AsApp {
|
|
// 当系统不可作为订阅方时,不可订阅
|
|
continue
|
|
}
|
|
status := subscribe.ApplyStatusReview
|
|
if s.ApprovalType == service.ApprovalTypeAuto {
|
|
status = subscribe.ApplyStatusSubscribe
|
|
cs, err := i.clusterService.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, c := range cs {
|
|
err := i.onlineSubscriber(ctx, c.Uuid, &gateway.SubscribeRelease{
|
|
Service: subscribeInfo.Service,
|
|
Application: appId,
|
|
Expired: "0",
|
|
})
|
|
|
|
if err != nil {
|
|
log.Errorf("online subscriber for cluster[%s] %v", c.Uuid, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
err = i.subscribeApplyService.Create(ctx, &subscribe.CreateApply{
|
|
Uuid: uuid.New().String(),
|
|
Service: subscribeInfo.Service,
|
|
Team: s.Team,
|
|
Application: appId,
|
|
ApplyTeam: appInfo.Team,
|
|
Reason: subscribeInfo.Reason,
|
|
Status: status,
|
|
Applier: userId,
|
|
})
|
|
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// 修改订阅表状态
|
|
subscribers, err := i.subscribeService.ListByApplication(ctx, subscribeInfo.Service, appId)
|
|
if err != nil {
|
|
return err
|
|
} else {
|
|
subscriberMap := utils.SliceToMap(subscribers, func(t *subscribe.Subscribe) string {
|
|
return t.Application
|
|
})
|
|
v, has := subscriberMap[appId]
|
|
if !has {
|
|
err = i.subscribeService.Create(ctx, &subscribe.CreateSubscribe{
|
|
Uuid: uuid.New().String(),
|
|
Service: subscribeInfo.Service,
|
|
Application: appId,
|
|
ApplyStatus: status,
|
|
From: subscribe.FromSubscribe,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else if v.ApplyStatus != subscribe.ApplyStatusSubscribe {
|
|
err = i.subscribeService.Save(ctx, v.Id, &subscribe.UpdateSubscribe{
|
|
ApplyStatus: &status,
|
|
})
|
|
}
|
|
|
|
}
|
|
|
|
apps = append(apps, appId)
|
|
}
|
|
if len(apps) == 0 {
|
|
return fmt.Errorf("no available apps")
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
var mcpDefaultConfig = `{
|
|
"mcpServers": {
|
|
"%s": {
|
|
"url": "%s"
|
|
}
|
|
}
|
|
}
|
|
`
|
|
|
|
func (i *imlCatalogueModule) ServiceDetail(ctx context.Context, sid string) (*catalogue_dto.ServiceDetail, error) {
|
|
// 获取服务的基本信息
|
|
s, err := i.serviceService.Get(ctx, sid)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get service failed: %w", err)
|
|
}
|
|
r, err := i.releaseService.GetRunning(ctx, s.Id)
|
|
if err != nil {
|
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
|
return &catalogue_dto.ServiceDetail{
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Document: "",
|
|
Basic: &catalogue_dto.ServiceBasic{
|
|
Team: auto.UUID(s.Team),
|
|
ApiNum: 0,
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
return nil, fmt.Errorf("get running release failed: %w", err)
|
|
}
|
|
|
|
countMap, err := i.subscribeService.CountMapByService(ctx, subscribe.ApplyStatusSubscribe, sid)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tags, err := i.serviceTagService.List(ctx, []string{sid}, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
tagIds := utils.SliceToSlice(tags, func(t *service_tag.Tag) string {
|
|
return t.Tid
|
|
}, func(t *service_tag.Tag) bool {
|
|
return t.Sid == sid
|
|
})
|
|
_, _, apiDocCommit, _, serviceDocCommit, err := i.releaseService.GetReleaseInfos(ctx, r.UUID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("get release apis failed: %w", err)
|
|
}
|
|
var apiDoc string
|
|
var apiNum int
|
|
if apiDocCommit != nil {
|
|
commit, err := i.apiDocService.GetDocCommit(ctx, apiDocCommit.Commit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
apiDoc = commit.Data.Content
|
|
apiNum = int(commit.Data.APICount)
|
|
}
|
|
|
|
var serviceDoc string
|
|
if serviceDocCommit != nil {
|
|
commit, err := i.serviceDocService.GetDocCommit(ctx, serviceDocCommit.Commit)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
serviceDoc = commit.Data.Content
|
|
}
|
|
invokeAddress, _ := i.settingService.Get(ctx, setting.KeyInvokeAddress)
|
|
sitePrefix, _ := i.settingService.Get(ctx, setting.KeySitePrefix)
|
|
mcpAccessAddress := ""
|
|
mcpAccessConfig := ""
|
|
if s.EnableMCP {
|
|
if sitePrefix != "" {
|
|
mcpAccessAddress = fmt.Sprintf("%s/openapi/v1/%s/%s/sse?apikey={your_api_key}", strings.TrimSuffix(sitePrefix, "/"), mcp_server.ServiceBasePath, s.Id)
|
|
mcpAccessConfig = fmt.Sprintf(mcpDefaultConfig, fmt.Sprintf("APIPark/%s", s.Name), mcpAccessAddress)
|
|
}
|
|
}
|
|
invokeMap, err := i.ProviderStatistics(ctx, time.Now().Add(-24*30*time.Hour), time.Now(), s.Id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &catalogue_dto.ServiceDetail{
|
|
Name: s.Name,
|
|
Description: s.Description,
|
|
Document: serviceDoc,
|
|
Basic: &catalogue_dto.ServiceBasic{
|
|
Team: auto.UUID(s.Team),
|
|
ApiNum: apiNum,
|
|
AppNum: int(countMap[s.Id]),
|
|
Tags: auto.List(tagIds),
|
|
Catalogue: auto.UUID(s.Catalogue),
|
|
Version: r.Version,
|
|
UpdateTime: auto.TimeLabel(r.CreateAt),
|
|
Logo: s.Logo,
|
|
ApprovalType: s.ApprovalType.String(),
|
|
ServiceKind: s.Kind.String(),
|
|
InvokeAddress: invokeAddress,
|
|
SitePrefix: sitePrefix,
|
|
EnableMCP: s.EnableMCP,
|
|
InvokeCount: invokeMap[s.Id],
|
|
},
|
|
APIDoc: apiDoc,
|
|
OpenAPIAddress: fmt.Sprintf("%s/api/v1/service/apidoc/%s", strings.TrimSuffix(sitePrefix, "/"), s.Id),
|
|
MCPServerAddress: mcpAccessAddress,
|
|
MCPAccessConfig: mcpAccessConfig,
|
|
}, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Services(ctx context.Context, keyword string) ([]*catalogue_dto.ServiceItem, error) {
|
|
|
|
serviceTags, err := i.serviceTagService.List(ctx, nil, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
serviceTagMap := utils.SliceToMapArrayO(serviceTags, func(t *service_tag.Tag) (string, string) {
|
|
return t.Sid, t.Tid
|
|
})
|
|
|
|
items, err := i.serviceService.SearchPublicServices(ctx, keyword)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
serviceIds := utils.SliceToSlice(items, func(i *service.Service) string {
|
|
return i.Id
|
|
})
|
|
overviewMap, err := i.serviceOverviewService.Map(ctx, serviceIds...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
serviceIds = utils.SliceToSlice(serviceIds, func(s string) string {
|
|
return s
|
|
}, func(s string) bool {
|
|
// 只展示已发布的服务
|
|
if info, ok := overviewMap[s]; ok && info.IsReleased {
|
|
return true
|
|
}
|
|
return false
|
|
})
|
|
if len(serviceIds) < 1 {
|
|
return nil, nil
|
|
}
|
|
|
|
subscriberCountMap, err := i.subscribeService.CountMapByService(ctx, subscribe.ApplyStatusSubscribe, serviceIds...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
invokeStatisticMap, err := i.ProviderStatistics(ctx, time.Now().Add(-24*30*time.Hour), time.Now(), serviceIds...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make([]*catalogue_dto.ServiceItem, 0, len(items))
|
|
for _, v := range items {
|
|
|
|
ov, ok := overviewMap[v.Id]
|
|
if !ok || ov.ReleaseApiCount < 1 {
|
|
continue
|
|
}
|
|
|
|
result = append(result, &catalogue_dto.ServiceItem{
|
|
Id: v.Id,
|
|
Name: v.Name,
|
|
Tags: auto.List(serviceTagMap[v.Id]),
|
|
Catalogue: auto.UUID(v.Catalogue),
|
|
SubscriberNum: subscriberCountMap[v.Id],
|
|
ApiNum: ov.ReleaseApiCount,
|
|
Description: v.Description,
|
|
Logo: v.Logo,
|
|
EnableMCP: v.EnableMCP,
|
|
ServiceKind: v.Kind.String(),
|
|
InvokeCount: invokeStatisticMap[v.Id],
|
|
})
|
|
}
|
|
sort.Slice(result, func(i, j int) bool {
|
|
if result[i].SubscriberNum != result[j].SubscriberNum {
|
|
return result[i].SubscriberNum > result[j].SubscriberNum
|
|
}
|
|
if result[i].ApiNum != result[j].ApiNum {
|
|
return result[i].ApiNum > result[j].ApiNum
|
|
}
|
|
return result[i].Name < result[j].Name
|
|
})
|
|
return result, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) recurseUpdateSort(ctx context.Context, parent string, sorts []*catalogue_dto.SortItem) error {
|
|
for index, item := range sorts {
|
|
s := index
|
|
err := i.catalogueService.Save(ctx, item.Id, &catalogue.EditCatalogue{
|
|
Parent: &parent,
|
|
Sort: &s,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(item.Children) < 1 {
|
|
continue
|
|
}
|
|
err = i.recurseUpdateSort(ctx, item.Id, item.Children)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Sort(ctx context.Context, sorts []*catalogue_dto.SortItem) error {
|
|
return i.transaction.Transaction(ctx, func(ctx context.Context) error {
|
|
err := i.recurseUpdateSort(ctx, "", sorts)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
all, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.root = NewRoot(all)
|
|
return nil
|
|
})
|
|
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Search(ctx context.Context, keyword string) ([]*catalogue_dto.Item, error) {
|
|
all, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if keyword == "" {
|
|
parentMap := make(map[string][]*catalogue.Catalogue)
|
|
nodeMap := make(map[string]*catalogue.Catalogue)
|
|
for _, v := range all {
|
|
if _, ok := parentMap[v.Parent]; !ok {
|
|
parentMap[v.Parent] = make([]*catalogue.Catalogue, 0)
|
|
}
|
|
parentMap[v.Parent] = append(parentMap[v.Parent], v)
|
|
nodeMap[v.Id] = v
|
|
}
|
|
return treeItems("", parentMap), nil
|
|
}
|
|
|
|
catalogues, err := i.catalogueService.Search(ctx, keyword, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if i.root == nil {
|
|
// 初始化
|
|
i.root = NewRoot(all)
|
|
}
|
|
items := make([]*catalogue_dto.Item, 0, len(catalogues))
|
|
|
|
return items, nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Create(ctx context.Context, input *catalogue_dto.CreateCatalogue) error {
|
|
parent := ""
|
|
if input.Parent != nil {
|
|
parent = *input.Parent
|
|
}
|
|
if input.Id == "" {
|
|
input.Id = uuid.New().String()
|
|
}
|
|
index := _sortMax
|
|
if input.Sort != nil {
|
|
index = *input.Sort
|
|
}
|
|
err := i.catalogueService.Create(ctx, &catalogue.CreateCatalogue{
|
|
Id: input.Id,
|
|
Name: input.Name,
|
|
Parent: parent,
|
|
Sort: index,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 重新初始化
|
|
catalogues, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.root = NewRoot(catalogues)
|
|
return nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Edit(ctx context.Context, id string, input *catalogue_dto.EditCatalogue) error {
|
|
err := i.catalogueService.Save(ctx, id, &catalogue.EditCatalogue{
|
|
Name: input.Name,
|
|
Parent: input.Parent,
|
|
Sort: input.Sort,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 重新初始化
|
|
catalogues, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.root = NewRoot(catalogues)
|
|
return nil
|
|
}
|
|
|
|
func (i *imlCatalogueModule) Delete(ctx context.Context, id string) error {
|
|
if id == "" {
|
|
return nil
|
|
}
|
|
list, err := i.catalogueService.Search(ctx, "", map[string]interface{}{
|
|
"parent": id,
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(list) > 0 {
|
|
return fmt.Errorf("该目录下存在子目录")
|
|
}
|
|
err = i.catalogueService.Delete(ctx, id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// 重新初始化
|
|
catalogues, err := i.catalogueService.List(ctx)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
i.root = NewRoot(catalogues)
|
|
return nil
|
|
}
|
|
|
|
// treeItems 获取子树
|
|
func treeItems(parentId string, parentMap map[string][]*catalogue.Catalogue) []*catalogue_dto.Item {
|
|
items := make([]*catalogue_dto.Item, 0)
|
|
if _, ok := parentMap[parentId]; ok {
|
|
for _, v := range parentMap[parentId] {
|
|
childItems := treeItems(v.Id, parentMap)
|
|
items = append(items, &catalogue_dto.Item{
|
|
Id: v.Id,
|
|
Name: v.Name,
|
|
Children: childItems,
|
|
Sort: v.Sort,
|
|
})
|
|
}
|
|
}
|
|
sort.Slice(items, func(i, j int) bool {
|
|
return items[i].Sort < items[j].Sort
|
|
})
|
|
return items
|
|
}
|