@@ -330,10 +330,16 @@ func (record *SAlertRecord) CustomizeCreate(
330330 query jsonutils.JSONObject ,
331331 data jsonutils.JSONObject ,
332332) error {
333- err := record .SMonitorScopedResource .CustomizeCreate (ctx , userCred , ownerId , query , data )
333+ /* err := record.SMonitorScopedResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
334334 if err != nil {
335335 return err
336+ }*/
337+ alert , err := AlertManager .GetAlert (record .AlertId )
338+ if err != nil {
339+ return errors .Wrapf (err , "GetAlert %s" , record .AlertId )
336340 }
341+ record .DomainId = alert .GetDomainId ()
342+ record .ProjectId = alert .GetProjectId ()
337343 obj , err := db .NewModelObject (AlertRecordManager )
338344 if err != nil {
339345 return errors .Wrapf (err , "NewModelObject %s" , AlertRecordManager .Keyword ())
@@ -532,3 +538,166 @@ func (manager *SAlertRecordManager) GetPropertyHistoryAlert(
532538 }
533539 return result , nil
534540}
541+
542+ // GetPropertyProjectAlertResourceCount 获取指定时间段内各项目下的报警资源数量
543+ func (manager * SAlertRecordManager ) GetPropertyProjectAlertResourceCount (
544+ ctx context.Context ,
545+ userCred mcclient.TokenCredential ,
546+ input monitor.ProjectAlertResourceCountInput ,
547+ ) (* monitor.ProjectAlertResourceCount , error ) {
548+ // 验证时间段参数
549+ if input .StartTime .IsZero () || input .EndTime .IsZero () {
550+ return nil , httperrors .NewInputParameterError ("start_time and end_time must be specified" )
551+ }
552+ if input .StartTime .After (input .EndTime ) {
553+ return nil , httperrors .NewInputParameterError ("start_time must be before end_time" )
554+ }
555+
556+ // 构建查询
557+ q := manager .Query ()
558+ q = q .GE ("created_at" , input .StartTime ).LE ("created_at" , input .EndTime )
559+ q = q .IsNotEmpty ("res_ids" )
560+
561+ // 应用权限过滤
562+ scope := rbacscope .ScopeSystem
563+ if input .Scope != "" {
564+ scope = rbacscope .TRbacScope (input .Scope )
565+ }
566+ q = manager .SMonitorScopedResourceManager .FilterByOwner (ctx , q , manager , userCred , userCred , scope )
567+
568+ // 如果指定了 ResType,添加过滤条件
569+ if input .ResType != "" {
570+ q = q .Equals ("res_type" , input .ResType )
571+ }
572+
573+ // 如果指定了 AlertId,添加过滤条件
574+ if input .AlertId != "" {
575+ q = q .Equals ("alert_id" , input .AlertId )
576+ }
577+
578+ // 执行查询获取所有记录
579+ alerts := make ([]SAlertRecord , 0 )
580+ err := q .All (& alerts )
581+ if err != nil {
582+ return nil , errors .Wrap (err , "query alert records" )
583+ }
584+
585+ // 按 scope 分组统计唯一资源数量
586+ // systemResourceSet = set of resource IDs (system scope)
587+ // domainResourceSet[domainId] = set of resource IDs (domain scope)
588+ // projectResourceSet[domainId][projectId] = set of resource IDs (project scope)
589+ systemResourceSet := sets .NewString ()
590+ domainResourceSet := make (map [string ]sets.String )
591+ projectResourceSet := make (map [string ]map [string ]sets.String )
592+ domainIds := sets .NewString ()
593+ projectIds := sets .NewString ()
594+
595+ for _ , alert := range alerts {
596+ if len (alert .ResIds ) == 0 {
597+ continue
598+ }
599+ domainId := alert .DomainId
600+ projectId := alert .ProjectId
601+
602+ // 解析 res_ids(逗号分隔)
603+ resIds := strings .Split (alert .ResIds , "," )
604+ for _ , resId := range resIds {
605+ resId = strings .TrimSpace (resId )
606+ if len (resId ) == 0 {
607+ continue
608+ }
609+
610+ // 根据 domainId 和 projectId 判断 scope
611+ if domainId == "" && projectId == "" {
612+ // system scope
613+ systemResourceSet .Insert (resId )
614+ } else if domainId != "" && projectId == "" {
615+ // domain scope
616+ domainIds .Insert (domainId )
617+ if domainResourceSet [domainId ] == nil {
618+ domainResourceSet [domainId ] = sets .NewString ()
619+ }
620+ domainResourceSet [domainId ].Insert (resId )
621+ } else if domainId != "" && projectId != "" {
622+ // project scope
623+ domainIds .Insert (domainId )
624+ projectIds .Insert (projectId )
625+ if projectResourceSet [domainId ] == nil {
626+ projectResourceSet [domainId ] = make (map [string ]sets.String )
627+ }
628+ if projectResourceSet [domainId ][projectId ] == nil {
629+ projectResourceSet [domainId ][projectId ] = sets .NewString ()
630+ }
631+ projectResourceSet [domainId ][projectId ].Insert (resId )
632+ }
633+ }
634+ }
635+
636+ // 获取项目和域的名称
637+ domainMap := make (map [string ]string )
638+ if domainIds .Len () > 0 {
639+ domains := []db.STenant {}
640+ err = db .TenantCacheManager .GetDomainQuery ().In ("id" , domainIds .List ()).All (& domains )
641+ if err != nil {
642+ return nil , errors .Wrap (err , "GetDomainQuery.In.All" )
643+ }
644+ for _ , domain := range domains {
645+ domainMap [domain .Id ] = domain .Name
646+ }
647+ }
648+
649+ projectMap := make (map [string ]string )
650+ if projectIds .Len () > 0 {
651+ projects := []db.STenant {}
652+ err = db .TenantCacheManager .GetTenantQuery ().In ("id" , projectIds .List ()).All (& projects )
653+ if err != nil {
654+ return nil , errors .Wrap (err , "GetTenantQuery.In.All" )
655+ }
656+ for _ , project := range projects {
657+ projectMap [project .Id ] = project .Name
658+ }
659+ }
660+
661+ // 构建返回结果
662+ result := & monitor.ProjectAlertResourceCount {
663+ Data : make ([]monitor.ProjectAlertResourceCountData , 0 ),
664+ }
665+
666+ // system scope
667+ if systemResourceSet .Len () > 0 {
668+ result .Data = append (result .Data , monitor.ProjectAlertResourceCountData {
669+ Scope : string (rbacscope .ScopeSystem ),
670+ ResCount : int64 (systemResourceSet .Len ()),
671+ })
672+ }
673+
674+ // domain scope
675+ for domainId , resourceSet := range domainResourceSet {
676+ if resourceSet .Len () > 0 {
677+ result .Data = append (result .Data , monitor.ProjectAlertResourceCountData {
678+ Scope : string (rbacscope .ScopeDomain ),
679+ DomainId : domainId ,
680+ Domain : domainMap [domainId ],
681+ ResCount : int64 (resourceSet .Len ()),
682+ })
683+ }
684+ }
685+
686+ // project scope
687+ for domainId , projects := range projectResourceSet {
688+ for projectId , resourceSet := range projects {
689+ if resourceSet .Len () > 0 {
690+ result .Data = append (result .Data , monitor.ProjectAlertResourceCountData {
691+ Scope : string (rbacscope .ScopeProject ),
692+ DomainId : domainId ,
693+ Domain : domainMap [domainId ],
694+ ProjectId : projectId ,
695+ Project : projectMap [projectId ],
696+ ResCount : int64 (resourceSet .Len ()),
697+ })
698+ }
699+ }
700+ }
701+
702+ return result , nil
703+ }
0 commit comments